Skip to content

Expose additional transport details to TransportListener#1762

Open
kwin wants to merge 2 commits into
masterfrom
feature/enhanced-transport-listener
Open

Expose additional transport details to TransportListener#1762
kwin wants to merge 2 commits into
masterfrom
feature/enhanced-transport-listener

Conversation

@kwin

@kwin kwin commented Jan 26, 2026

Copy link
Copy Markdown
Member

For HTTP Transporters this is:

  • HTTP Version
  • SSL Protocol (only HTTPS)
  • SSL Cipher Suite (only HTTPS)
  • Compression Algorithm (if used)
  • Transport Size (if it differs from data size)

This closes #1761

Following this checklist to help us incorporate your
contribution quickly and easily:

  • Your pull request should address just one issue, without pulling in other changes.
  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  • Each commit in the pull request should have a meaningful subject line and body.
    Note that commits might be squashed by a maintainer on merge.
  • Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied.
    This may not always be possible but is a best-practice.
  • Run mvn verify to make sure basic checks pass.
    A more thorough check will be performed on your pull request automatically.
  • You have run the integration tests successfully (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.

@kwin

kwin commented Jan 26, 2026

Copy link
Copy Markdown
Member Author

@cstamas WDYT about this proposal?

@kwin kwin force-pushed the feature/enhanced-transport-listener branch 5 times, most recently from f4e7be9 to b74d406 Compare January 27, 2026 11:49
@cstamas

cstamas commented Jan 27, 2026

Copy link
Copy Markdown
Member

Looks good

@kwin kwin force-pushed the feature/enhanced-transport-listener branch from b74d406 to 865b07b Compare January 28, 2026 13:05
@kwin kwin force-pushed the feature/enhanced-transport-listener branch 3 times, most recently from d7dbb29 to 379fc1c Compare July 3, 2026 18:10
@kwin kwin requested a review from cstamas July 3, 2026 18:12
@kwin kwin marked this pull request as ready for review July 3, 2026 18:12
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
@kwin kwin force-pushed the feature/enhanced-transport-listener branch from 379fc1c to 74227e3 Compare July 3, 2026 18:55

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 copy transportProperties from 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 have getTransportProperties() return null

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 TransportPropertyKey marker interface extensible for non-HTTP transports
  • Thoughtful backwards compat with deprecated overloads in AbstractTransporter and TransportListener
  • Solid test coverage in TransportListenerNotifyingInputStreamTest and shared HttpTransporterTest

🤖 This review was generated by ForgeBot using a maker/checker pattern (reviewer + independent verifier). All 5 findings were independently confirmed.

@gnodet

gnodet commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Thanks for the thorough rework, @kwin! The new commit addresses all 5 findings from my earlier review:

  1. transportProperties field is now private final with emptyMap() default — immutability contract restored
  2. HttpTransportPropertiesBuilder.build() returns unmodifiableMap — no more mutable reference leak
  3. ✅ Apache transporter now reports transport properties on all task types (Get, Peek, Put) via a dedicated HttpRequestExecutor
  4. ✅ The new transportPropertiesAvailable() method is a clean design — it decouples property notification from the transportStarted() transfer lifecycle, solving the PeekTask inconsistency without overloading the event semantics
  5. ✅ Dead SSL_1_0 / SSL_2_0 enum values removed

The transportPropertiesAvailable() approach is a nice architectural improvement over the original design — separating concerns between "transfer is starting" and "transport metadata is available" makes the API much clearer.


🤖 This follow-up was generated by ForgeBot. Reviewing new commits on a previously reviewed PR.

gnodet added a commit to gnodet/maven-resolver that referenced this pull request Jul 13, 2026
@kwin kwin force-pushed the feature/enhanced-transport-listener branch from 0d76a45 to 91b6933 Compare July 13, 2026 19:26
Expose transport properties for all tasks (Get, Peek, Put).
Reliably capture SSL context from ApacheTransporter with a dedicated
request executor.
@kwin kwin force-pushed the feature/enhanced-transport-listener branch from 91b6933 to 0ecd838 Compare July 13, 2026 19:32

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

  1. properties field visibility in HttpTransportPropertiesBuilder — The properties field has package-private visibility (no access modifier) in a public final SPI class. It should be private final to enforce proper encapsulation.

  2. Mutable-backed unmodifiable map from build()Collections.unmodifiableMap(properties) creates a view backed by the same HashMap. If the builder were reused after build(), the previously returned map would reflect mutations. Using Collections.unmodifiableMap(new HashMap<>(properties)) or Map.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

  1. 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 the Key enum, not the HttpVersion enum.

  2. Self-referencing Javadoc link in HttpTransportProperty.java{@link #SSL_PROTOCOL} should be {@link SslProtocol} to reference the value type, not the constant being documented.

  3. Broken @see reference in HttpTransportPropertiesBuilder@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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
* @since NEXT
private final Map<TransferEvent.TransportPropertyKey, Object> properties = new HashMap<>();

this.properties.put(Key.HTTP_VERSION, version);
}

public HttpTransportPropertiesBuilder withSslProtocol(String name) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

Suggested change
public HttpTransportPropertiesBuilder withSslProtocol(String name) {
public Map<TransferEvent.TransportPropertyKey, Object> build() {
return Collections.unmodifiableMap(new HashMap<>(properties));
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expose additional transport details via TransportListener

3 participants