|
17 | 17 |
|
18 | 18 | package com.rabbitmq.client.amqp.impl;
|
19 | 19 |
|
20 |
| -import static com.rabbitmq.client.amqp.Resource.State.*; |
| 20 | +import static com.rabbitmq.client.amqp.Resource.State.CLOSED; |
| 21 | +import static com.rabbitmq.client.amqp.Resource.State.CLOSING; |
| 22 | +import static com.rabbitmq.client.amqp.Resource.State.OPEN; |
| 23 | +import static com.rabbitmq.client.amqp.Resource.State.OPENING; |
| 24 | +import static com.rabbitmq.client.amqp.Resource.State.RECOVERING; |
21 | 25 | import static com.rabbitmq.client.amqp.impl.ExceptionUtils.convert;
|
| 26 | +import static com.rabbitmq.client.amqp.impl.Tuples.pair; |
22 | 27 | import static com.rabbitmq.client.amqp.impl.Utils.supportFilterExpressions;
|
23 | 28 | import static com.rabbitmq.client.amqp.impl.Utils.supportSetToken;
|
24 | 29 | import static java.lang.System.nanoTime;
|
25 | 30 | import static java.time.Duration.ofNanos;
|
26 | 31 |
|
27 |
| -import com.rabbitmq.client.amqp.*; |
| 32 | +import com.rabbitmq.client.amqp.Address; |
| 33 | +import com.rabbitmq.client.amqp.AmqpException; |
| 34 | +import com.rabbitmq.client.amqp.Connection; |
| 35 | +import com.rabbitmq.client.amqp.ConnectionSettings; |
| 36 | +import com.rabbitmq.client.amqp.Consumer; |
| 37 | +import com.rabbitmq.client.amqp.ConsumerBuilder; |
| 38 | +import com.rabbitmq.client.amqp.Management; |
28 | 39 | import com.rabbitmq.client.amqp.ObservationCollector;
|
| 40 | +import com.rabbitmq.client.amqp.Publisher; |
| 41 | +import com.rabbitmq.client.amqp.PublisherBuilder; |
| 42 | +import com.rabbitmq.client.amqp.RpcClient; |
| 43 | +import com.rabbitmq.client.amqp.RpcClientBuilder; |
| 44 | +import com.rabbitmq.client.amqp.RpcServer; |
| 45 | +import com.rabbitmq.client.amqp.RpcServerBuilder; |
| 46 | +import com.rabbitmq.client.amqp.impl.Tuples.Pair; |
29 | 47 | import com.rabbitmq.client.amqp.impl.Utils.RunnableWithException;
|
30 | 48 | import com.rabbitmq.client.amqp.impl.Utils.StopWatch;
|
31 | 49 | import com.rabbitmq.client.amqp.metrics.MetricsCollector;
|
@@ -89,7 +107,7 @@ final class AmqpConnection extends ResourceBase implements Connection {
|
89 | 107 | private final List<RpcClient> rpcClients = new CopyOnWriteArrayList<>();
|
90 | 108 | private final List<RpcServer> rpcServers = new CopyOnWriteArrayList<>();
|
91 | 109 | private final TopologyListener topologyListener;
|
92 |
| - private volatile EntityRecovery entityRecovery; |
| 110 | + private final EntityRecovery entityRecovery; |
93 | 111 | private final AtomicBoolean recoveringConnection = new AtomicBoolean(false);
|
94 | 112 | private final DefaultConnectionSettings<?> connectionSettings;
|
95 | 113 | private final Supplier<SessionHandler> sessionHandlerSupplier;
|
@@ -118,7 +136,9 @@ final class AmqpConnection extends ResourceBase implements Connection {
|
118 | 136 | AmqpConnectionBuilder.AmqpRecoveryConfiguration recoveryConfiguration =
|
119 | 137 | builder.recoveryConfiguration();
|
120 | 138 |
|
121 |
| - this.topologyListener = createTopologyListener(builder); |
| 139 | + Pair<TopologyListener, EntityRecovery> topologyInfra = createTopologyInfrastructure(builder); |
| 140 | + this.topologyListener = topologyInfra.v1(); |
| 141 | + this.entityRecovery = topologyInfra.v2(); |
122 | 142 |
|
123 | 143 | Executor de =
|
124 | 144 | builder.dispatchingExecutor() == null
|
@@ -344,20 +364,25 @@ private static String extractNode(org.apache.qpid.protonj2.client.Connection con
|
344 | 364 | return node;
|
345 | 365 | }
|
346 | 366 |
|
347 |
| - TopologyListener createTopologyListener(AmqpConnectionBuilder builder) { |
| 367 | + Pair<TopologyListener, EntityRecovery> createTopologyInfrastructure( |
| 368 | + AmqpConnectionBuilder builder) { |
348 | 369 | TopologyListener topologyListener;
|
| 370 | + EntityRecovery entityRecovery; |
349 | 371 | if (builder.recoveryConfiguration().topology()) {
|
350 | 372 | RecordingTopologyListener rtl =
|
351 | 373 | new RecordingTopologyListener(
|
352 | 374 | "topology-listener-connection-" + this.name(), this.environment.recoveryEventLoop());
|
353 |
| - this.entityRecovery = new EntityRecovery(this, rtl); |
| 375 | + entityRecovery = new EntityRecovery(this, rtl); |
354 | 376 | topologyListener = rtl;
|
355 | 377 | } else {
|
356 | 378 | topologyListener = TopologyListener.NO_OP;
|
| 379 | + entityRecovery = null; |
357 | 380 | }
|
358 |
| - return builder.topologyListener() == null |
359 |
| - ? topologyListener |
360 |
| - : TopologyListener.compose(List.of(builder.topologyListener(), topologyListener)); |
| 381 | + topologyListener = |
| 382 | + builder.topologyListener() == null |
| 383 | + ? topologyListener |
| 384 | + : TopologyListener.compose(List.of(builder.topologyListener(), topologyListener)); |
| 385 | + return pair(topologyListener, entityRecovery); |
361 | 386 | }
|
362 | 387 |
|
363 | 388 | private BiConsumer<org.apache.qpid.protonj2.client.Connection, DisconnectionEvent>
|
@@ -455,12 +480,21 @@ private void recoverAfterConnectionFailure(
|
455 | 480 | LOGGER.debug("Reconnected '{}' to {}", this.name(), this.currentConnectionLabel());
|
456 | 481 | try {
|
457 | 482 | if (recoveryConfiguration.topology()) {
|
| 483 | + boolean managementPreviouslyClosed = this.management.isClosed(); |
458 | 484 | this.management.init();
|
459 | 485 | LOGGER.debug("Recovering topology of connection '{}'...", this.name());
|
460 | 486 | this.recoverTopology();
|
461 | 487 | this.recoverConsumers();
|
462 | 488 | this.recoverPublishers();
|
463 | 489 | LOGGER.debug("Recovered topology of connection '{}'.", this.name());
|
| 490 | + if (managementPreviouslyClosed) { |
| 491 | + LOGGER.debug("Management was closed before recovery, closing it again"); |
| 492 | + try { |
| 493 | + this.closeManagement(); |
| 494 | + } catch (Exception e) { |
| 495 | + LOGGER.info("Error while (re)closing management after recovery"); |
| 496 | + } |
| 497 | + } |
464 | 498 | }
|
465 | 499 | LOGGER.info(
|
466 | 500 | "Recovered connection '{}' to {}", this.name(), this.currentConnectionLabel());
|
@@ -924,6 +958,22 @@ public String toString() {
|
924 | 958 | return this.name();
|
925 | 959 | }
|
926 | 960 |
|
| 961 | + private void authenticate(String username, String password) { |
| 962 | + State state = this.state(); |
| 963 | + if (state == OPEN) { |
| 964 | + LOGGER.debug("Setting new token for connection {}", this.name); |
| 965 | + long start = nanoTime(); |
| 966 | + ((AmqpManagement) management()).setToken(password); |
| 967 | + LOGGER.debug( |
| 968 | + "Set new token for connection {} in {} ms", |
| 969 | + this.name, |
| 970 | + ofNanos(nanoTime() - start).toMillis()); |
| 971 | + } else { |
| 972 | + LOGGER.debug( |
| 973 | + "Could not set new token for connection {} because its state is {}", this.name(), state); |
| 974 | + } |
| 975 | + } |
| 976 | + |
927 | 977 | static class NativeConnectionWrapper {
|
928 | 978 |
|
929 | 979 | private final org.apache.qpid.protonj2.client.Connection connection;
|
|
0 commit comments