Skip to content

Commit 147e0f2

Browse files
committed
Handle JMX Collisions
Previously, if two DefaultConnectionContexts were created in a single JVM, registration of the JMX ByteBuf monitors would cause an ugly message to be logged. While this wasn't terminal, it wasn't a great experience. In addition, the possibility of multiple DefaultConnectionContexts is a valid one as you might need to connect to multiple host/port endpoints. This change updates the name of the MBeans to include endpoint to properly handle the valid case of multiple DefaultConnectionContexts for multiple endpoints. It also warns about multiple duplicate DefaultConnectionContexts for the same endpoint and removes the previous MBean, replacing it with the new one. It also unregisters the MBean during disposal as part of normal cleanup. [resolves #836]
1 parent d46c067 commit 147e0f2

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/_DefaultConnectionContext.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import javax.annotation.PostConstruct;
3939
import javax.annotation.PreDestroy;
4040
import javax.management.JMException;
41+
import javax.management.MalformedObjectNameException;
4142
import javax.management.ObjectName;
4243
import java.lang.management.ManagementFactory;
4344
import java.time.Duration;
@@ -57,6 +58,8 @@
5758
@Value.Immutable
5859
abstract class _DefaultConnectionContext implements ConnectionContext {
5960

61+
private static final int DEFAULT_PORT = 443;
62+
6063
private static final int RECEIVE_BUFFER_SIZE = 10 * 1024 * 1024;
6164

6265
private static final int SEND_BUFFER_SIZE = 10 * 1024 * 1024;
@@ -70,6 +73,16 @@ abstract class _DefaultConnectionContext implements ConnectionContext {
7073
public final void dispose() {
7174
getConnectionPool().ifPresent(PoolResources::dispose);
7275
getThreadPool().dispose();
76+
77+
try {
78+
ObjectName name = getByteBufAllocatorObjectName();
79+
80+
if (ManagementFactory.getPlatformMBeanServer().isRegistered(name)) {
81+
ManagementFactory.getPlatformMBeanServer().unregisterMBean(name);
82+
}
83+
} catch (JMException e) {
84+
this.logger.error("Unable to register ByteBufAllocator MBean", e);
85+
}
7386
}
7487

7588
/**
@@ -146,7 +159,6 @@ public Mono<Void> trust(String host, int port) {
146159
/**
147160
* The hostname of the API root. Typically something like {@code api.run.pivotal.io}.
148161
*/
149-
@Nullable
150162
abstract String getApiHost();
151163

152164
/**
@@ -222,11 +234,21 @@ LoopResources getThreadPool() {
222234
@PostConstruct
223235
void monitorByteBufAllocator() {
224236
try {
225-
ManagementFactory.getPlatformMBeanServer()
226-
.registerMBean(new ByteBufAllocatorMetricProviderWrapper(PooledByteBufAllocator.DEFAULT), ObjectName.getInstance("org.cloudfoundry.reactor:type=ByteBufAllocator"));
237+
ObjectName name = getByteBufAllocatorObjectName();
238+
239+
if (ManagementFactory.getPlatformMBeanServer().isRegistered(name)) {
240+
this.logger.warn("MBean '{}' is already registered and will be removed. You should only have a single DefaultConnectionContext per endpoint.", name);
241+
ManagementFactory.getPlatformMBeanServer().unregisterMBean(name);
242+
}
243+
244+
ManagementFactory.getPlatformMBeanServer().registerMBean(new ByteBufAllocatorMetricProviderWrapper(PooledByteBufAllocator.DEFAULT), name);
227245
} catch (JMException e) {
228246
this.logger.error("Unable to register ByteBufAllocator MBean", e);
229247
}
230248
}
231249

250+
private ObjectName getByteBufAllocatorObjectName() throws MalformedObjectNameException {
251+
return ObjectName.getInstance(String.format("org.cloudfoundry.reactor:type=ByteBufAllocator,endpoint=%s/%d", getApiHost(), getPort().orElse(DEFAULT_PORT)));
252+
}
253+
232254
}

cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/DefaultConnectionContextTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,21 @@ public void getInfo() throws Exception {
6868
.verify(Duration.ofSeconds(5));
6969
}
7070

71+
@Test
72+
public void multipleInstances() {
73+
DefaultConnectionContext first = DefaultConnectionContext.builder()
74+
.apiHost("test-host")
75+
.build();
76+
77+
DefaultConnectionContext second = DefaultConnectionContext.builder()
78+
.apiHost("test-host")
79+
.build();
80+
81+
first.monitorByteBufAllocator();
82+
second.monitorByteBufAllocator();
83+
84+
first.dispose();
85+
second.dispose();
86+
}
87+
7188
}

0 commit comments

Comments
 (0)