Skip to content

Release 14.1#54

Merged
CesarCoelho merged 11 commits into
masterfrom
v14.1
Jul 18, 2026
Merged

Release 14.1#54
CesarCoelho merged 11 commits into
masterfrom
v14.1

Conversation

@CesarCoelho

Copy link
Copy Markdown
Collaborator

Release of version 14.1.

Changes since 14.0

  • Vendors the W3C XML Schema files instead of downloading them at build time (removes the build's dependency on network access to w3.org)
  • Fixes a race condition and silent failures in the LazyMessageBody decoding
  • Restores the log-and-continue handling of NotFoundException during decoding
  • No longer reports empty message bodies as failed decodes
  • Loads the consumer.properties file only once per JVM

To be Squash and Merged, per RELEASING.md.

🤖 Generated with Claude Code

CesarCoelho and others added 11 commits July 4, 2026 11:27
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The generator-interfaces build downloaded XMLSchema.xsd, XMLSchema.dtd,
and datatypes.dtd live from www.w3.org on every build to generate the
w3c.xsd JAXB classes. These are frozen 2009 standards, and the live
fetch made the build non-hermetic and prone to HTTP 429 rate-limiting
from W3C (which broke CI).

Commit the three files under src/main/xsd-ref/, point the process-w3c-xsd
xjc execution at the local copy, and remove the wagon-maven-plugin
download executions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
For a synchronous INVOKE with a registered listener, the same lazily
decoded message body is read by two threads: the consumer thread woken
by the interaction handler and the dispatcher thread delivering the same
message to the listener. decodeMessageBody() was not synchronized and
set decodedBody=true before allocating messageParts, so the losing
thread saw "already decoded", read the still-null messageParts, and
failed with an NPE far from the cause. The window only opens for a
non-empty ACK body, which is why it went unnoticed. Make the method
synchronized.

Also stop swallowing decode failures: a NotFoundException left
messageParts null and readers would NPE later with no hint of the
cause. Rethrow it as MALException like the sibling branch, and make
repeated reads after a failed decode fail with a MALException instead
of an NPE.

Verified against the NMF e2e testbed (a sync install invoke with a
populated ACK reproduced the NPE deterministically on the unfixed code
and passes with this fix) and the full MAL testbed suite.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rethrowing the NotFoundException as MALException changed the behavior of
a long-standing path: callers above may push the error back to consumers
or brokers that previously carried on after the logged warning. Keep the
original swallowing behavior; the repeated-read guard still reports a
descriptive MALException instead of an NPE when a previous decode
attempt has failed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
loadConsumerProperties() re-read and re-applied consumer.properties on
every call. Consumers such as the CTT invoke it once per connection (via
NMFConsumer.init() and retrieveProvidersFromDirectory()), so the file was
loaded repeatedly during startup, producing a stream of "Reloading
properties: consumer.properties" log lines.

Guard it with a dedicated "ConsumerPropertiesLoadedFlag" so the file is
loaded at most once. The flag is deliberately independent from the
provider's "PropertiesLoadedFlag": an application acting as both a
consumer and a provider must still load both property files.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The repeated-read guard added in 277f7c8 throws a MALException when a
body is read with decodedBody=true but messageParts=null, on the
assumption that this only happens after a decode failure. That
assumption was wrong: an empty body is passed to the constructor as a
null messageParts array, so every argument-less request and every empty
acknowledgement hit the guard, and getElementCount() logged it at SEVERE
during encoding on both the provider and consumer sides.

Guarantee the invariant "decodedBody == true implies messageParts !=
null" at both assignment sites:
 - the constructor coalesces a null messageParts to an empty array;
 - the swallowed-NotFoundException branch (the tolerated operation-not-
   found path restored in 07d8f6e) degrades to an empty body instead of
   leaving messageParts null.

Empty bodies now encode as zero-part bodies as they did before 277f7c8,
the SEVERE spam is gone, and the guard remains as defensive insurance
for a genuinely inconsistent state.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@CesarCoelho
CesarCoelho merged commit d4f425c into master Jul 18, 2026
77 of 80 checks passed
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.

1 participant