Expose additional transport details to TransportListener#1762
Conversation
|
@cstamas WDYT about this proposal? |
f4e7be9 to
b74d406
Compare
|
Looks good |
b74d406 to
865b07b
Compare
d7dbb29 to
379fc1c
Compare
For HTTP Transporters this is: - HTTP Version - SSL Protocol (only HTTPS) - SSL Cipher Suite (only HTTPS) - Compression Algorithm (if used and supported by HTTP Client impl) This closes #1761
379fc1c to
74227e3
Compare
gnodet
left a comment
There was a problem hiding this comment.
AI Review — PR #1762: Expose additional transport details to TransportListener
Hi @kwin, thanks for this feature — the TransportPropertyKey design with HTTP-specific enum implementation is well-structured and extensible.
🔴 TransferEvent.transportProperties field visibility (high)
The new transportProperties field is package-private (no access modifier) while every other field in TransferEvent is private final. This breaks the class's immutability contract. Additionally:
- The Builder's
copy()constructor doesn't copytransportPropertiesfrom the prototype - The field defaults to
null, but the Javadoc says "may be empty" (implying never null) - Events built without calling
setTransportProperties()(INITIATED, PROGRESSED, CORRUPTED, FAILED, SUCCEEDED) will havegetTransportProperties()returnnull
Fix: Make the field private final, initialize to Collections.emptyMap() in the Builder, and copy in copy().
🔴 HttpTransportPropertiesBuilder.build() returns mutable reference (high)
build() returns the raw internal HashMap reference. While TransferEvent.Builder.setTransportProperties() wraps it in Collections.unmodifiableMap(), the builder retains a reference to the mutable map. Continuing to mutate the builder after build() would affect the already-returned map. Fix: Return Collections.unmodifiableMap(properties) from build().
⚠️ Apache transporter PUT doesn't report transport properties (medium)
ApacheTransporter.implPut still uses the deprecated 3-arg utilPut(), so PUT operations never report transport properties. Jetty's implPut does report them. This is an inconsistency across transporters.
⚠️ JdkTransporter.implPeek fires transportStarted() (medium)
This PR adds a transportStarted() call in implPeek() that didn't exist before. PeekTask's Javadoc explicitly says its listener is "always a noop." Apache and Jetty don't fire events during peek. This is currently harmless but creates an inconsistent contract.
💡 Dead SslProtocol enum values (low)
SSL_1_0 and SSL_2_0 are declared but fromStandardName() doesn't handle them — they're unreachable. These protocols were removed from Java years ago. Either add cases (for completeness) or remove the constants.
What works well:
- Clean
TransportPropertyKeymarker interface extensible for non-HTTP transports - Thoughtful backwards compat with deprecated overloads in
AbstractTransporterandTransportListener - Solid test coverage in
TransportListenerNotifyingInputStreamTestand sharedHttpTransporterTest
🤖 This review was generated by ForgeBot using a maker/checker pattern (reviewer + independent verifier). All 5 findings were independently confirmed.
|
Thanks for the thorough rework, @kwin! The new commit addresses all 5 findings from my earlier review:
The 🤖 This follow-up was generated by ForgeBot. Reviewing new commits on a previously reviewed PR. |
0d76a45 to
91b6933
Compare
Expose transport properties for all tasks (Get, Peek, Put). Reliably capture SSL context from ApacheTransporter with a dedicated request executor.
91b6933 to
0ecd838
Compare
gnodet
left a comment
There was a problem hiding this comment.
Review Summary
Nice work on this, @kwin! The overall API design with TransportPropertyKey as a marker interface and per-transport enum implementations is clean and extensible without breaking backward compatibility. The separation of transportPropertiesAvailable() from the transfer lifecycle events is a good architectural choice.
I found a few issues worth addressing:
Medium Severity
-
propertiesfield visibility inHttpTransportPropertiesBuilder— Thepropertiesfield has package-private visibility (no access modifier) in apublic finalSPI class. It should beprivate finalto enforce proper encapsulation. -
Mutable-backed unmodifiable map from
build()—Collections.unmodifiableMap(properties)creates a view backed by the sameHashMap. If the builder were reused afterbuild(), the previously returned map would reflect mutations. UsingCollections.unmodifiableMap(new HashMap<>(properties))orMap.copyOf(properties)would produce a truly detached snapshot. Current callers are safe (they don't reuse the builder), but as a public SPI class the API contract should be defensive.
Low Severity
-
Broken Javadoc link in
HttpTransportProperty.java—{@link #HttpVersion}should be{@link HttpVersion}(without the#). The#prefix means "member of the current type" which refers to theKeyenum, not theHttpVersionenum. -
Self-referencing Javadoc link in
HttpTransportProperty.java—{@link #SSL_PROTOCOL}should be{@link SslProtocol}to reference the value type, not the constant being documented. -
Broken
@seereference inHttpTransportPropertiesBuilder—@see TransportListener#transportStarted(long, long, Map)references a non-existent 3-parameter method. Should be@see TransportListener#transportPropertiesAvailable(Map).
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of Guillaume Nodet
|
|
||
| /** | ||
| * Builder for HTTP transport properties used in {@link TransportListener#transportStarted(long, long, Map)}. | ||
| * @since NEXT |
There was a problem hiding this comment.
This field has package-private visibility (no access modifier). Since this is a public final SPI class, it should be private final to enforce encapsulation and prevent same-package classes from accessing the mutable map directly.
| * @since NEXT | |
| private final Map<TransferEvent.TransportPropertyKey, Object> properties = new HashMap<>(); |
| this.properties.put(Key.HTTP_VERSION, version); | ||
| } | ||
|
|
||
| public HttpTransportPropertiesBuilder withSslProtocol(String name) { |
There was a problem hiding this comment.
Collections.unmodifiableMap(properties) creates an unmodifiable view backed by the same HashMap. If the builder is reused after calling build(), the previously returned map would reflect mutations. Consider using a defensive copy:
| public HttpTransportPropertiesBuilder withSslProtocol(String name) { | |
| public Map<TransferEvent.TransportPropertyKey, Object> build() { | |
| return Collections.unmodifiableMap(new HashMap<>(properties)); | |
| } |
For HTTP Transporters this is:
This closes #1761
Following this checklist to help us incorporate your
contribution quickly and easily:
Note that commits might be squashed by a maintainer on merge.
This may not always be possible but is a best-practice.
mvn verifyto make sure basic checks pass.A more thorough check will be performed on your pull request automatically.
mvn -Prun-its verify).If your pull request is about ~20 lines of code you don't need to sign an
Individual Contributor License Agreement if you are unsure
please ask on the developers list.
To make clear that you license your contribution under
the Apache License Version 2.0, January 2004
you have to acknowledge this by using the following check-box.