From 0d7bc312dfef36fafc271aadd0ace51c059df9de Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Tue, 25 Nov 2025 14:17:38 -0500 Subject: [PATCH 1/7] Feat: Send `userAgent` with client identity This patch teaches session negotiation to send a user agent of the form "com.bloomberg.bmq(javaXX.YY.ZZ):AA.BB.CC", where "XX.YY.ZZ" is the version of Java this SDK is running on, and "AA.BB.CC" is the SDK version. It additionally sets the user agent to in the `PlainConsumerIT` and `PlainProducerIT` integration test clients to different strings. These clients are not simple users of this SDK, and construct the sockets they communicate on directly. It is thus useful to distinguish them on the broker from normal users of the SDK. Signed-off-by: Patrick M. Niedzielski --- .../com/bloomberg/bmq/impl/TcpBrokerConnection.java | 9 ++++++++- .../bloomberg/bmq/impl/infr/msg/ClientIdentity.java | 12 +++++++++++- .../com/bloomberg/bmq/impl/infr/util/SystemUtil.java | 8 ++++++-- .../bmq/impl/infr/codec/JsonDecoderUtilTest.java | 2 +- .../impl/infr/proto/SchemaEventImplBuilderTest.java | 2 +- .../java/com/bloomberg/bmq/it/PlainConsumerIT.java | 3 ++- .../java/com/bloomberg/bmq/it/PlainProducerIT.java | 3 ++- 7 files changed, 31 insertions(+), 8 deletions(-) diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/TcpBrokerConnection.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/TcpBrokerConnection.java index 47c4b9cc..96c86568 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/TcpBrokerConnection.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/TcpBrokerConnection.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Bloomberg Finance L.P. + * Copyright 2022-2025 Bloomberg Finance L.P. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -373,9 +373,16 @@ private NegotiationMessageChoice createNegoMsg() { clientIdentity.setClusterName(""); clientIdentity.setClusterNodeId(-1); clientIdentity.setSdkLanguage(ClientLanguage.E_JAVA); + clientIdentity.setUserAgent(constructUserAgent()); return negoMsgChoice; } + private String constructUserAgent() { + String javaVersion = "java" + SystemUtil.getJavaVersionString(); + String sdkVersion = VersionUtil.getJarVersion(); + return "com.bloomberg.bmq(" + javaVersion + "):" + sdkVersion; + } + private WriteStatus negotiate() throws IOException { if (negotiationMsg == null) { negotiationMsg = createNegoMsg(); diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/ClientIdentity.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/ClientIdentity.java index 47f87c8d..8f1d6445 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/ClientIdentity.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/ClientIdentity.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Bloomberg Finance L.P. + * Copyright 2022-2025 Bloomberg Finance L.P. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ public class ClientIdentity { private String clusterName; private Integer clusterNodeId; private ClientLanguage sdkLanguage; + private String userAgent; public ClientIdentity() { init(); @@ -48,6 +49,7 @@ private void init() { clusterName = ""; clusterNodeId = -1; sdkLanguage = ClientLanguage.E_UNKNOWN; + userAgent = ""; } public Integer protocolVersion() { @@ -138,6 +140,14 @@ public void setSdkLanguage(ClientLanguage value) { sdkLanguage = value; } + public String userAgent() { + return userAgent; + } + + public void setUserAgent(String value) { + userAgent = value; + } + public Object createNewInstance() { return new ClientIdentity(); } diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/util/SystemUtil.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/util/SystemUtil.java index d735c86f..8d4feee7 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/util/SystemUtil.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/util/SystemUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Bloomberg Finance L.P. + * Copyright 2022-2025 Bloomberg Finance L.P. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,7 +48,7 @@ public static JavaVersion getJavaVersion() { JavaVersion result = JavaVersion.JAVA_UNSUPPORTED; try { - String version = System.getProperty("java.version"); + String version = getJavaVersionString(); result = Arrays.stream(JavaVersion.values()) @@ -63,6 +63,10 @@ public static JavaVersion getJavaVersion() { return result; } + public static String getJavaVersionString() { + return System.getProperty("java.version"); + } + public static int getProcessId() { int pid = 0; String vmname = null; diff --git a/bmq-sdk/src/test/java/com/bloomberg/bmq/impl/infr/codec/JsonDecoderUtilTest.java b/bmq-sdk/src/test/java/com/bloomberg/bmq/impl/infr/codec/JsonDecoderUtilTest.java index ba217461..dc1dc60e 100644 --- a/bmq-sdk/src/test/java/com/bloomberg/bmq/impl/infr/codec/JsonDecoderUtilTest.java +++ b/bmq-sdk/src/test/java/com/bloomberg/bmq/impl/infr/codec/JsonDecoderUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Bloomberg Finance L.P. + * Copyright 2022-2025 Bloomberg Finance L.P. * * 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/bmq-sdk/src/test/java/com/bloomberg/bmq/impl/infr/proto/SchemaEventImplBuilderTest.java b/bmq-sdk/src/test/java/com/bloomberg/bmq/impl/infr/proto/SchemaEventImplBuilderTest.java index 44f879d3..1289ae78 100644 --- a/bmq-sdk/src/test/java/com/bloomberg/bmq/impl/infr/proto/SchemaEventImplBuilderTest.java +++ b/bmq-sdk/src/test/java/com/bloomberg/bmq/impl/infr/proto/SchemaEventImplBuilderTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Bloomberg Finance L.P. + * Copyright 2022-2025 Bloomberg Finance L.P. * * 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/bmq-sdk/src/test/java/com/bloomberg/bmq/it/PlainConsumerIT.java b/bmq-sdk/src/test/java/com/bloomberg/bmq/it/PlainConsumerIT.java index 820d0644..636aa439 100644 --- a/bmq-sdk/src/test/java/com/bloomberg/bmq/it/PlainConsumerIT.java +++ b/bmq-sdk/src/test/java/com/bloomberg/bmq/it/PlainConsumerIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Bloomberg Finance L.P. + * Copyright 2022-2025 Bloomberg Finance L.P. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -115,6 +115,7 @@ public static ByteBuffer[] getLastMessage(int port, Uri uri) clientIdentity.setClusterName(""); clientIdentity.setClusterNodeId(-1); clientIdentity.setSdkLanguage(ClientLanguage.E_JAVA); + clientIdentity.setUserAgent("com.bloomberg.bmq.it.PlainConsumerIT"); SchemaEventBuilder schemaBuilder = new SchemaEventBuilder(); diff --git a/bmq-sdk/src/test/java/com/bloomberg/bmq/it/PlainProducerIT.java b/bmq-sdk/src/test/java/com/bloomberg/bmq/it/PlainProducerIT.java index 09024f50..b0e5bdf4 100644 --- a/bmq-sdk/src/test/java/com/bloomberg/bmq/it/PlainProducerIT.java +++ b/bmq-sdk/src/test/java/com/bloomberg/bmq/it/PlainProducerIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Bloomberg Finance L.P. + * Copyright 2022-2025 Bloomberg Finance L.P. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -117,6 +117,7 @@ public static void sendMessage( clientIdentity.setClusterName(""); clientIdentity.setClusterNodeId(-1); clientIdentity.setSdkLanguage(ClientLanguage.E_JAVA); + clientIdentity.setUserAgent("com.bloomberg.bmq.it.PlainProducerIT"); SchemaEventBuilder schemaBuilder = new SchemaEventBuilder(); From bef38d2d02f247247d3ef9fb7d3e257d6119ad2c Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Tue, 25 Nov 2025 15:14:46 -0500 Subject: [PATCH 2/7] Feat: Let user specify a user agent prefix This patch exposes an option in `SessionOptions` that a user can set, which will be prefixed to the beginning of the user agent sent to the broker during session negotiation. This prefix does not need to be set, but if it is, it must consist only of printable ASCII characters and must be less than 128 characters long. Signed-off-by: Patrick M. Niedzielski --- .../com/bloomberg/bmq/SessionOptions.java | 48 ++++++++++++++++++- .../bmq/impl/TcpBrokerConnection.java | 6 ++- .../bmq/impl/infr/net/ConnectionOptions.java | 19 +++++++- 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/SessionOptions.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/SessionOptions.java index bdb8c8e4..48019843 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/SessionOptions.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/SessionOptions.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Bloomberg Finance L.P. + * Copyright 2022-2025 Bloomberg Finance L.P. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,6 +62,10 @@ * HostHealthMonitor} interface responsible for notifying the session when the health of the * host machine has changed. A {@code hostHealthMonitor} must be specified in oder for queues * opened through the session to suspend on unhealthy hosts. + *
  • {@code userAgentPrefix}: String to include in the user agent for broker telemetry. This + * string must only contain printable characters and must be less than 128 characters long. + * This is provided for libraries that are wrapping this SDK. Applications directly using the + * SDK are encouraged NOT to set this value. * * *

    Thread Safety

    @@ -215,6 +219,8 @@ public int highWaterMark() { private final HostHealthMonitor hostHealthMonitor; + private final String userAgentPrefix; + private SessionOptions() { brokerUri = DEFAULT_URI; startTimeout = DEFAULT_START_TIMEOUT; @@ -226,6 +232,7 @@ private SessionOptions() { configureQueueTimeout = QUEUE_OPERATION_TIMEOUT; closeQueueTimeout = QUEUE_OPERATION_TIMEOUT; hostHealthMonitor = null; + userAgentPrefix = ""; } private SessionOptions(Builder builder) { @@ -239,6 +246,7 @@ private SessionOptions(Builder builder) { configureQueueTimeout = builder.configureQueueTimeout; closeQueueTimeout = builder.closeQueueTimeout; hostHealthMonitor = builder.hostHealthMonitor; + userAgentPrefix = builder.userAgentPrefix; } /** @@ -383,6 +391,16 @@ public HostHealthMonitor hostHealthMonitor() { return hostHealthMonitor; } + /** + * Returns the string that will be prefixed to the user agent used by {@link + * com.bloomberg.bmq.Session} to identify itself to the broker. + * + * @return String user agent string prefix + */ + public String userAgentPrefix() { + return userAgentPrefix; + } + /** Helper class to create a {@code SesssionOptions} object with custom settings. */ public static class Builder { private URI brokerUri; @@ -397,6 +415,9 @@ public static class Builder { private Duration closeQueueTimeout; private HostHealthMonitor hostHealthMonitor; + + private String userAgentPrefix; + /** * Creates a {@code SesssionOptions} object based on this {@code Builder} properties. * @@ -417,6 +438,7 @@ private Builder(SessionOptions options) { configureQueueTimeout = options.configureQueueTimeout; closeQueueTimeout = options.closeQueueTimeout; hostHealthMonitor = options.hostHealthMonitor; + userAgentPrefix = options.userAgentPrefix; } /** @@ -558,5 +580,29 @@ public Builder setHostHealthMonitor(HostHealthMonitor value) { hostHealthMonitor = Argument.expectNonNull(value, "host health monitor"); return this; } + + /** + * Sets the user agent prefix. This string is prefixed to a user agent constructed by the + * SDK. This is intended ONLY for other libraries that wrap this SDK to identify themselves + * for broker telemetry. Applications that are directly using this SDK are encouraged not to + * set this. + * + * @param value String user agent prefix + * @return Builder this object + * @throws NullPointerException if the specified value is null + * @throws IllegalArgumentException in case the specified value contains non-ASCII + * characters, contains non-printable characters (i.e., control characters), or is + * longer than 127 characters. + */ + public Builder setUserAgentPrefix(String value) { + Argument.expectNonNull(value, "user agent prefix"); + Argument.expectCondition( + value.codePoints().allMatch(c -> c < 128 && !Character.isISOControl(c)), + "user agent prefix must be printable ASCII"); + Argument.expectCondition( + value.length() < 128, "user agent prefix must be shorter than 128 characters"); + userAgentPrefix = value; + return this; + } } } diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/TcpBrokerConnection.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/TcpBrokerConnection.java index 96c86568..ca7a5696 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/TcpBrokerConnection.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/TcpBrokerConnection.java @@ -378,9 +378,13 @@ private NegotiationMessageChoice createNegoMsg() { } private String constructUserAgent() { + String prefix = ""; + if (connectionOptions.userAgentPrefix().length() > 0) { + prefix = connectionOptions.userAgentPrefix() + " "; + } String javaVersion = "java" + SystemUtil.getJavaVersionString(); String sdkVersion = VersionUtil.getJarVersion(); - return "com.bloomberg.bmq(" + javaVersion + "):" + sdkVersion; + return prefix + "com.bloomberg.bmq(" + javaVersion + "):" + sdkVersion; } private WriteStatus negotiate() throws IOException { diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/net/ConnectionOptions.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/net/ConnectionOptions.java index bc585cc4..f95631a3 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/net/ConnectionOptions.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/net/ConnectionOptions.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Bloomberg Finance L.P. + * Copyright 2022-2025 Bloomberg Finance L.P. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,12 +39,14 @@ public final class ConnectionOptions { private int startNumRetries = DEFAULT_START_NUM_RETRIES; private Duration startRetryInterval = DEFAULT_START_RETRY_INTERVAL; private WriteBufferWaterMark writeWaterMark = new WriteBufferWaterMark(); + private String userAgentPrefix = ""; public ConnectionOptions() {} public ConnectionOptions(SessionOptions sesOpts) { brokerUri = sesOpts.brokerUri(); writeWaterMark = sesOpts.writeBufferWaterMark(); + userAgentPrefix = sesOpts.userAgentPrefix(); } public ConnectionOptions setBrokerUri(URI value) { @@ -80,6 +82,17 @@ public ConnectionOptions setWriteBufferWaterMark(WriteBufferWaterMark value) { return this; } + public ConnectionOptions setUserAgentPrefix(String value) { + Argument.expectNonNull(value, "user agent prefix"); + Argument.expectCondition( + value.codePoints().allMatch(c -> c < 128 && !Character.isISOControl(c)), + "user agent prefix must be printable ASCII"); + Argument.expectCondition( + value.length() < 128, "user agent prefix must be shorter than 128 characters"); + userAgentPrefix = value; + return this; + } + public URI brokerUri() { return brokerUri; } @@ -99,4 +112,8 @@ public Duration startRetryInterval() { public WriteBufferWaterMark writeBufferWaterMark() { return writeWaterMark; } + + public String userAgentPrefix() { + return userAgentPrefix; + } } From 9c1662a6adb61115d4cbc90092f5f5a8b7b82b26 Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Tue, 25 Nov 2025 17:52:17 -0500 Subject: [PATCH 3/7] wip! ahunsehunsaoesuhaeosuhsaoehunsaoehunsaoehnsuahoentuhaoesu Signed-off-by: Patrick M. Niedzielski --- .../src/test/java/com/bloomberg/bmq/util/TestHelpers.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bmq-sdk/src/test/java/com/bloomberg/bmq/util/TestHelpers.java b/bmq-sdk/src/test/java/com/bloomberg/bmq/util/TestHelpers.java index 2a74eeee..a8ddb518 100644 --- a/bmq-sdk/src/test/java/com/bloomberg/bmq/util/TestHelpers.java +++ b/bmq-sdk/src/test/java/com/bloomberg/bmq/util/TestHelpers.java @@ -82,7 +82,10 @@ public static void compareWithFileContent( v1 = in1.read(); v2 = in2.read(); assertTrue(v1 >= 0); - assertEquals(v1, v2); + assertEquals( + v1, + v2, + "Found mismatch at byte " + i + ": " + (char) v1 + ", " + (char) v2); } } } From f135002c57e93b5d3df570a3fed01bbd21fd0aa6 Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Tue, 25 Nov 2025 18:44:52 -0500 Subject: [PATCH 4/7] golden test Signed-off-by: Patrick M. Niedzielski --- ...ent_a326573a-2c1e-42a2-afdc-da184456c118.bin | Bin 248 -> 248 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bmq-sdk/src/test/resources/data/msg_control_nego_client_a326573a-2c1e-42a2-afdc-da184456c118.bin b/bmq-sdk/src/test/resources/data/msg_control_nego_client_a326573a-2c1e-42a2-afdc-da184456c118.bin index 212cc5f56e39aec6c62a604238a854297a0e31ed..d825560769724c219c0f370fd18a3d59dfa9ccf4 100644 GIT binary patch delta 11 Scmeyt_=Ay|fq`)%^H%^CL<4{T delta 11 Scmeyt_=Ay|fq`Kn^H%^CKm&gO From f8b38ecd6d4dea27c63501aead52c16197e32f96 Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Tue, 2 Dec 2025 15:33:07 -0500 Subject: [PATCH 5/7] Fix: Avoid possible `this` escape before subclass is fully initialized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes several warnings on JDK 21 and later, in which a subclass can override a method called from its superclass’s constructor, letting it see a partially formed `this` object. Signed-off-by: Patrick M. Niedzielski --- .../bloomberg/bmq/impl/infr/msg/ControlMessageChoice.java | 2 +- .../bmq/impl/infr/msg/NegotiationMessageChoice.java | 2 +- .../java/com/bloomberg/bmq/impl/infr/proto/AckHeader.java | 2 +- .../com/bloomberg/bmq/impl/infr/proto/AckMessageImpl.java | 8 ++++---- .../bloomberg/bmq/impl/infr/proto/AckMessageIterator.java | 2 +- .../bmq/impl/infr/proto/BinaryMessageProperty.java | 2 +- .../bmq/impl/infr/proto/BoolMessageProperty.java | 2 +- .../bmq/impl/infr/proto/ByteMessageProperty.java | 2 +- .../com/bloomberg/bmq/impl/infr/proto/ConfirmHeader.java | 2 +- .../bmq/impl/infr/proto/ConfirmMessageIterator.java | 2 +- .../bmq/impl/infr/proto/Int32MessageProperty.java | 2 +- .../bmq/impl/infr/proto/Int64MessageProperty.java | 2 +- .../bmq/impl/infr/proto/MessagePropertyHeader.java | 2 +- .../com/bloomberg/bmq/impl/infr/proto/OptionHeader.java | 2 +- .../com/bloomberg/bmq/impl/infr/proto/PushHeader.java | 2 +- .../bloomberg/bmq/impl/infr/proto/PushMessageImpl.java | 2 +- .../bmq/impl/infr/proto/PushMessageIterator.java | 3 ++- .../java/com/bloomberg/bmq/impl/infr/proto/PutHeader.java | 2 +- .../bloomberg/bmq/impl/infr/proto/PutMessageIterator.java | 2 +- .../bmq/impl/infr/proto/ShortMessageProperty.java | 2 +- .../bmq/impl/infr/proto/StringMessageProperty.java | 2 +- 21 files changed, 25 insertions(+), 24 deletions(-) diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/ControlMessageChoice.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/ControlMessageChoice.java index d6123730..b93095c7 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/ControlMessageChoice.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/ControlMessageChoice.java @@ -187,7 +187,7 @@ public final DisconnectResponse disconnectResponse() { return disconnectResponse; } - public void init() { + public final void init() { configureQueueStream = null; configureQueueStreamResponse = null; configureStream = null; diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/NegotiationMessageChoice.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/NegotiationMessageChoice.java index 5dd7b58a..62a553b2 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/NegotiationMessageChoice.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/NegotiationMessageChoice.java @@ -58,7 +58,7 @@ public final BrokerResponse brokerResponse() { return brokerResponse; } - public void init() { + public final void init() { clientIdentity = null; brokerResponse = null; } diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckHeader.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckHeader.java index 11e07ede..d8ac63b4 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckHeader.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckHeader.java @@ -24,7 +24,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class AckHeader implements Streamable { +public final class AckHeader implements Streamable { // This class represents header for an 'ACK' event. An 'ACK' event is the // event sent by the broker to a client in response to a post message on // queue. Such event is optional, depending on flags used at queue open. diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckMessageImpl.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckMessageImpl.java index c86bca4f..9d04c494 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckMessageImpl.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckMessageImpl.java @@ -105,23 +105,23 @@ public AckMessageImpl( setQueueId(queueId); } - public void setStatus(ResultCodes.AckResult status) { + public final void setStatus(ResultCodes.AckResult status) { int value = ResultCodeUtils.intFromAckResult(status); statusAndCorrelationId = (statusAndCorrelationId & CORRID_MASK) | (value << STATUS_START_IDX); } - public void setCorrelationId(CorrelationIdImpl value) { + public final void setCorrelationId(CorrelationIdImpl value) { int id = value.toInt(); statusAndCorrelationId = (statusAndCorrelationId & STATUS_MASK) | (id & CORRID_MASK); correlationId = value; } - public void setQueueId(int value) { + public final void setQueueId(int value) { queueId = value; } - public void setMessageGUID(final MessageGUID value) { + public final void setMessageGUID(final MessageGUID value) { value.toBinary(messageGUID); } diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckMessageIterator.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckMessageIterator.java index 096dcf00..45debf8a 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckMessageIterator.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckMessageIterator.java @@ -22,7 +22,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class AckMessageIterator extends MessageIterator implements Iterator { +public final class AckMessageIterator extends MessageIterator implements Iterator { static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/BinaryMessageProperty.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/BinaryMessageProperty.java index 26338ff5..9c7a9813 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/BinaryMessageProperty.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/BinaryMessageProperty.java @@ -15,7 +15,7 @@ */ package com.bloomberg.bmq.impl.infr.proto; -public class BinaryMessageProperty extends MessageProperty { +public final class BinaryMessageProperty extends MessageProperty { public BinaryMessageProperty() { super(PropertyType.BINARY, MessagePropertyHeader.MAX_PROPERTY_VALUE_LENGTH); diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/BoolMessageProperty.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/BoolMessageProperty.java index 1b670e2e..8af2925e 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/BoolMessageProperty.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/BoolMessageProperty.java @@ -15,7 +15,7 @@ */ package com.bloomberg.bmq.impl.infr.proto; -public class BoolMessageProperty extends MessageProperty { +public final class BoolMessageProperty extends MessageProperty { public BoolMessageProperty() { super(PropertyType.BOOL, Byte.SIZE); diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ByteMessageProperty.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ByteMessageProperty.java index 76ad84ef..de9e1cb2 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ByteMessageProperty.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ByteMessageProperty.java @@ -15,7 +15,7 @@ */ package com.bloomberg.bmq.impl.infr.proto; -public class ByteMessageProperty extends MessageProperty { +public final class ByteMessageProperty extends MessageProperty { public ByteMessageProperty() { super(PropertyType.BYTE, Byte.SIZE); diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ConfirmHeader.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ConfirmHeader.java index addbcfd4..146abf7d 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ConfirmHeader.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ConfirmHeader.java @@ -21,7 +21,7 @@ import com.bloomberg.bmq.impl.infr.util.BitUtil; import java.io.IOException; -public class ConfirmHeader implements Streamable { +public final class ConfirmHeader implements Streamable { // This class represents header for a 'CONFIRM' event. A 'CONFIRM' event // is the event sent by a client to the broker to signify it's done // processing a specific message and the broker can dispose of it. diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ConfirmMessageIterator.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ConfirmMessageIterator.java index 666402a4..27a25425 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ConfirmMessageIterator.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ConfirmMessageIterator.java @@ -21,7 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class ConfirmMessageIterator extends MessageIterator { +public final class ConfirmMessageIterator extends MessageIterator { static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/Int32MessageProperty.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/Int32MessageProperty.java index bf87098c..97cfcc99 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/Int32MessageProperty.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/Int32MessageProperty.java @@ -17,7 +17,7 @@ import java.nio.ByteBuffer; -public class Int32MessageProperty extends MessageProperty { +public final class Int32MessageProperty extends MessageProperty { public Int32MessageProperty() { super(PropertyType.INT32, Integer.SIZE); diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/Int64MessageProperty.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/Int64MessageProperty.java index 5fd10c7f..7228f3ff 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/Int64MessageProperty.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/Int64MessageProperty.java @@ -17,7 +17,7 @@ import java.nio.ByteBuffer; -public class Int64MessageProperty extends MessageProperty { +public final class Int64MessageProperty extends MessageProperty { public Int64MessageProperty() { super(PropertyType.INT64, Long.SIZE); diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertyHeader.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertyHeader.java index 40d800c2..1b43f396 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertyHeader.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertyHeader.java @@ -21,7 +21,7 @@ import java.io.DataOutput; import java.io.IOException; -public class MessagePropertyHeader { +public final class MessagePropertyHeader { // This class represents the header for a message property in a PUT or // PUSH message. diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/OptionHeader.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/OptionHeader.java index 5266b50a..0ed40788 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/OptionHeader.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/OptionHeader.java @@ -25,7 +25,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class OptionHeader implements Streamable { +public final class OptionHeader implements Streamable { // This class represents the header for an option. In a typical // implementation usage, every Option class will start by an // 'OptionHeader' member. diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushHeader.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushHeader.java index f6c66cb7..cde23502 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushHeader.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushHeader.java @@ -24,7 +24,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class PushHeader { +public final class PushHeader { static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); // This struct represents the header for a 'PUSH' event. A 'PUSH' event is diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushMessageImpl.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushMessageImpl.java index 26c4dc4d..ce0e71c7 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushMessageImpl.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushMessageImpl.java @@ -45,7 +45,7 @@ public PushMessageImpl() { reset(); } - public void reset() { + public final void reset() { header = new PushHeader(); appData = new ApplicationData(); options = new Options(); diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushMessageIterator.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushMessageIterator.java index 181e6124..85e3b911 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushMessageIterator.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushMessageIterator.java @@ -20,7 +20,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class PushMessageIterator extends MessageIterator implements Iterator { +public final class PushMessageIterator extends MessageIterator + implements Iterator { static Logger logger = LoggerFactory.getLogger(PushMessageIterator.class); diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PutHeader.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PutHeader.java index 9d73b902..0a63a9fe 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PutHeader.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PutHeader.java @@ -22,7 +22,7 @@ import com.bloomberg.bmq.impl.infr.util.BitUtil; import java.io.IOException; -public class PutHeader { +public final class PutHeader { // This class represents the header for a 'PUT' event. A 'PUT' event is // the event sent by a client to the broker to post message on queue(s). diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PutMessageIterator.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PutMessageIterator.java index 7194c8c3..889fa167 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PutMessageIterator.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PutMessageIterator.java @@ -21,7 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class PutMessageIterator extends MessageIterator implements Iterator { +public final class PutMessageIterator extends MessageIterator implements Iterator { static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ShortMessageProperty.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ShortMessageProperty.java index 3a4798c0..3dae80c4 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ShortMessageProperty.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ShortMessageProperty.java @@ -17,7 +17,7 @@ import java.nio.ByteBuffer; -public class ShortMessageProperty extends MessageProperty { +public final class ShortMessageProperty extends MessageProperty { public ShortMessageProperty() { super(PropertyType.SHORT, Short.SIZE); diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/StringMessageProperty.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/StringMessageProperty.java index cb3bade8..0e10331c 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/StringMessageProperty.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/StringMessageProperty.java @@ -20,7 +20,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class StringMessageProperty extends MessageProperty { +public final class StringMessageProperty extends MessageProperty { static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); From c541376f6f70057213c354626ded339995ba8965 Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Tue, 2 Dec 2025 15:46:07 -0500 Subject: [PATCH 6/7] Fix: avoid implicit cast in compound assignment This patch fixes a warning on newer JDKs, where we narrow a `long` down to an `int` during a compound assignment later on in the function. This `long` is the result of the `readByte()` call on the line changed by this patch, and we might as well store it as an `int` early on. [WARNING] /Users/pniedzielski/Projects/bloomberg/blazingmq-sdk-java/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertiesImpl.java:[234,24] implicit cast from long to int in compound assignment is possibly lossy Signed-off-by: Patrick M. Niedzielski --- .../bloomberg/bmq/impl/infr/proto/MessagePropertiesImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertiesImpl.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertiesImpl.java index bc5f6347..86da37b4 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertiesImpl.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertiesImpl.java @@ -216,7 +216,7 @@ public int streamInOld(T input) throws IOExc } // Read padding bytes - final long numPaddingBytes = input.readByte(); + final int numPaddingBytes = input.readByte(); // Skip padding bytes if (input.skip(numPaddingBytes - 1) != numPaddingBytes - 1) { From a69bdb91bd86710d35413dea1cc0ce95ad0c6ac7 Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Tue, 2 Dec 2025 16:13:30 -0500 Subject: [PATCH 7/7] Fix: avoid implicit byte cast in compound assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes an implicit conversion from `int` to `byte` that newer JDKs warn about. [WARNING] blazingmq-sdk-java/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/EventHeader.java:[255,31] implicit cast from int to byte in compound assignment is possibly lossy This is ultimately because bitshifts in Java only operate on integral types, not bytes, so `typeAsByte` is promoted to a `byte` before being or’d with `typeSpecificUpdate`. Signed-off-by: Patrick M. Niedzielski --- .../java/com/bloomberg/bmq/impl/infr/proto/EventHeader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/EventHeader.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/EventHeader.java index e89e4e5c..8f175cb9 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/EventHeader.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/EventHeader.java @@ -252,7 +252,7 @@ public void setControlEventEncodingType(EncodingType type) { byte typeAsByte = (byte) (type.toInt()); // Set those bits to represent 'type' - typeSpecificUpdate |= (typeAsByte << CONTROL_EVENT_ENCODING_START_IDX); + typeSpecificUpdate |= (byte) (typeAsByte << CONTROL_EVENT_ENCODING_START_IDX); setTypeSpecific(typeSpecificUpdate); }