Skip to content

fix(activemq): restore xmlns on <broker> and correct pendingMessageLimitStrategy structure - #211

Merged
natechadwick merged 1 commit into
mainfrom
bugfix/210-activemq-pending-message-limit-strategy
Sep 8, 2026
Merged

fix(activemq): restore xmlns on <broker> and correct pendingMessageLimitStrategy structure#211
natechadwick merged 1 commit into
mainfrom
bugfix/210-activemq-pending-message-limit-strategy

Conversation

@natechadwick-intsof

Copy link
Copy Markdown
Collaborator

Summary

Two T2.2 ActiveMQ hardening regressions in system/Tools/jetty/defaults/etc/activemq/activemq.xml, both surfaced by the post-T2.12 strict XSD validation:

  1. Missing xmlns on <broker> (the fix(activemq): restore xmlns on <broker> element (regression from T2.2 PR #166 reformat) #208 fix — supersedes the still-open fix(activemq): restore xmlns on <broker> element (regression from T2.2 PR #166 reformat) #209 PR)
  2. Wrong element names in the pending-message-limit block (the fix(activemq): correct pendingMessageLimitStrategy structure (regression from T2.2 PR #166) #210 fix)

After the #208 xmlns fix lands, XSD validation loads activemq.xsd and then immediately rejects the next layer of T2.2 element-name bugs at line 61:

cvc-complex-type.2.4.a: Invalid content was found starting with element
'{"http://activemq.apache.org/schema/core":constantPendingMessageLimit}'.
One of '{"http://activemq.apache.org/schema/core":fileQueueCursor,
"http://activemq.apache.org/schema/core":storeCursor,
"http://activemq.apache.org/schema/core":vmQueueCursor,
WC[##other:"http://activemq.apache.org/schema/core"]}' is expected.

What's actually wrong (the #210 piece)

The T2.2 PR mixed up two ActiveMQ policy mechanisms that look similar but mean very different things:

T2.2 wrote XSD expects What it controls
<pendingQueuePolicy> <pendingMessageLimitStrategy> (parent) cap on count per consumer
<constantPendingMessageLimit value="1000"/> <constantPendingMessageLimitStrategy limit="1000"/> (child) constant cap with limit attribute (not value)

<pendingQueuePolicy> is for selecting the queue cursor (how pending messages are stored: fileQueueCursor / storeCursor / vmQueueCursor). It is not a cap on count. The XSD's <xs:any namespace='##other'/> wildcard on that element does not allow <constantPendingMessageLimit> because the element is in the same ActiveMQ namespace, not a different one.

The "cap pending message count per queue" intent of the original T2.2 block is preserved with the corrected elements.

Diff

     <broker
+        xmlns="http://activemq.apache.org/schema/core"
         useShutdownHook="false"
         ...
+    <!--
+         The xmlns="http://activemq.apache.org/schema/core" on <broker> is
+         required ... (full block, see file)
+    -->
     <broker
+        xmlns="http://activemq.apache.org/schema/core"
         ...
                     <policyEntry queue=">" ...>
-                    <!-- T2.2: cap pending message count per queue ... -->
-                    <pendingQueuePolicy>
-                        <constantPendingMessageLimit value="1000"/>
-                    </pendingQueuePolicy>
+                    <!-- T2.2: cap pending message count per queue ...
+                         ActiveMQ has two superficially similar policy
+                         elements that do very different things: ... -->
+                    <pendingMessageLimitStrategy>
+                        <constantPendingMessageLimitStrategy limit="1000"/>
+                    </pendingMessageLimitStrategy>
                     </policyEntry>

Why bundled into one PR

The #208 xmlns fix and the #210 element-name fix are both in the same file, both surface under the same root cause (post-T2.12 strict XSD validation), and were originally written as a T2.2 hardening followup. The #208 PR (#209) is still open and unmerged; this PR includes that change and supersedes it. After this lands, #209 can be closed without merging.

Why this only surfaced now (and not earlier)

The T2.12 hardening PR set FEATURE_SECURE_PROCESSING=true on the default DocumentBuilderFactory, which makes Xerces more aggressive about loading and applying schema URLs from xsi:schemaLocation. Pre-T2.12, the parser was looser about elementFormDefault='qualified' mismatches and silently ignored unreferenced elements; post-T2.12, every element in <broker> is validated against activemq.xsd and any typo becomes a hard failure. The activemq.xml has been technically malformed since the T2.2 PR was merged, but the parser only just got strict enough to surface the bug.

There may be more layers of T2.2 typos after this one — XSD validation typically fails on the first error, so the rest of the file is unvalidated. We'll find out on the next restart.

Verification

  • python3 -c "import xml.etree.ElementTree as ET; ET.parse('...activemq.xml')" — well-formed.
  • Namespace check: <broker> is in http://activemq.apache.org/schema/core; <pendingMessageLimitStrategy> and <constantPendingMessageLimitStrategy> are too.
  • After deploy + restart: the Failed to load: class path resource [activemq.xml] ERROR chain disappears from server.log. The in-VM broker starts; PERCUSSION.EMAIL, PERCUSSION.PUBLISHING, PERCUSSION.NOTIFICATIONS JMS listeners connect cleanly.
  • xmllint --schema activemq.xsd activemq.xml --noout (if xmllint is available) — exits 0.

Refs #208, #210

Co-Authored by Mavis Mavis-Code using MiniMax-M3 with agent mavis.

After PR #208/#209 restored the xmlns on <broker> (so the XSD loads),
the post-T2.12 default DocumentBuilderFactory keeps validating and
catches the next layer of T2.2 element-name bugs in the same file:

  SAXParseException; lineNumber: 61; columnNumber: 68;
  cvc-complex-type.2.4.a: Invalid content was found starting with element
  '{"http://activemq.apache.org/schema/core":constantPendingMessageLimit}'.
  One of '{"http://activemq.apache.org/schema/core":fileQueueCursor,
  "http://activemq.apache.org/schema/core":storeCursor,
  "http://activemq.apache.org/schema/core":vmQueueCursor,
  WC[##other:"http://activemq.apache.org/schema/core"]}' is expected.

The T2.2 PR mixed up two superficially similar ActiveMQ policy
mechanisms that do very different things:

  T2.2 wrote           XSD expects                 What it controls
  ---------------      ----------------------      -------------------
  <pendingQueuePolicy> <pendingMessageLimitStrategy> (parent) cap on count
                                                    per consumer
  <constantPending-    <constantPending-            (child) constant
  MessageLimit         MessageLimitStrategy          cap with 'limit'
  value="1000"/>       limit="1000"/>                attribute

<pendingQueuePolicy> selects the queue cursor (fileQueueCursor /
storeCursor / vmQueueCursor) -- i.e., how pending messages are *stored*,
not how many are kept. The XSD's <xs:any namespace='##other'/> wildcard
on that element does NOT allow <constantPendingMessageLimit> because the
element is in the same ActiveMQ namespace, not a different one. Hence
"Invalid content was found starting with element constantPendingMessageLimit."

Fix: replace the wrong parent/child pair with the correct XSD-valid
<pendingMessageLimitStrategy>/<constantPendingMessageLimitStrategy> pair,
and use the `limit` attribute (not `value`). The "cap pending message
count per queue" intent of the original T2.2 block is preserved.

This PR also pulls in the #208 fix (xmlns on <broker> + the explanatory
comment). The #208 PR (#209) is still open and is superseded by this one;
it can be closed without merging.

Refs #208, #210

> Co-Authored by Mavis Mavis-Code using MiniMax-M3 with agent mavis.
@natechadwick
natechadwick merged commit f405ee5 into main Sep 8, 2026
3 checks passed
@natechadwick
natechadwick deleted the bugfix/210-activemq-pending-message-limit-strategy branch September 8, 2026 18:22
natechadwick pushed a commit that referenced this pull request Sep 8, 2026
…in + ConnectionFactory (#213)

* fix(activemq): two XSD-namespace-correct element bugs from T2.2 PR #166

After PR #208/#209 restored the xmlns on <broker> (so the XSD loads),
the post-T2.12 default DocumentBuilderFactory keeps validating and
catches the next layer of T2.2 element-name bugs in the same file:

  SAXParseException; lineNumber: 61; columnNumber: 68;
  cvc-complex-type.2.4.a: Invalid content was found starting with element
  '{"http://activemq.apache.org/schema/core":constantPendingMessageLimit}'.
  One of '{"http://activemq.apache.org/schema/core":fileQueueCursor,
  "http://activemq.apache.org/schema/core":storeCursor,
  "http://activemq.apache.org/schema/core":vmQueueCursor,
  WC[##other:"http://activemq.apache.org/schema/core"]}' is expected.

The T2.2 PR mixed up two superficially similar ActiveMQ policy
mechanisms that do very different things:

  T2.2 wrote           XSD expects                 What it controls
  ---------------      ----------------------      -------------------
  <pendingQueuePolicy> <pendingMessageLimitStrategy> (parent) cap on count
                                                    per consumer
  <constantPending-    <constantPending-            (child) constant
  MessageLimit         MessageLimitStrategy          cap with 'limit'
  value="1000"/>       limit="1000"/>                attribute

<pendingQueuePolicy> selects the queue cursor (fileQueueCursor /
storeCursor / vmQueueCursor) -- i.e., how pending messages are *stored*,
not how many are kept. The XSD's <xs:any namespace='##other'/> wildcard
on that element does NOT allow <constantPendingMessageLimit> because the
element is in the same ActiveMQ namespace, not a different one. Hence
"Invalid content was found starting with element constantPendingMessageLimit."

Fix: replace the wrong parent/child pair with the correct XSD-valid
<pendingMessageLimitStrategy>/<constantPendingMessageLimitStrategy> pair,
and use the `limit` attribute (not `value`). The "cap pending message
count per queue" intent of the original T2.2 block is preserved.

This PR also pulls in the #208 fix (xmlns on <broker> + the explanatory
comment). The #208 PR (#209) is still open and is superseded by this one;
it can be closed without merging.

Refs #208, #210

> Co-Authored by Mavis Mavis-Code using MiniMax-M3 with agent mavis.

* fix(activemq): add in-VM user credentials to simpleAuthenticationPlugin + ConnectionFactory

The T2.2 ActiveMQ hardening PR (#166/#167) configured
`<simpleAuthenticationPlugin anonymousAccessAllowed="false"/>` but did
not add any users and did not update the in-VM ActiveMQConnectionFactory
in perc-mq.xml / ear/WEB-INF/jetty-env.xml to provide credentials. The
in-VM transport (vm://localhost) sends anonymous (no user / no password)
connections by default, so every JMS listener (PERCUSSION.EMAIL,
PERCUSSION.PUBLISHING, PERCUSSION.NOTIFICATIONS) gets
`User name [null] or password is invalid` and retries in a 5-second
FixedBackOff loop (currentAttempts climbs to 30+ within a minute).

Fix has three parts:

1. activemq.xml: add a single 'rhythmyx' user to the
   simpleAuthenticationPlugin via the userPasswords and userGroups
   attributes. userGroups 'users,admins' grants both consume/produce
   on queues/topics and admin operations; the default ActiveMQ
   SimpleAuthorizationMap is permissive (no <simpleAuthorizationMap>
   is required to grant access to PERCUSSION.* queues).
   anonymousAccessAllowed stays 'false' so the security posture is
   preserved for any future network listener.

2. perc-mq.xml: configure the Jetty-bound ActiveMQConnectionFactory
   (java:/ConnectionFactory) with setUserName / setPassword via Jetty's
   <Property> indirection. Operators can override the default at
   install time via -Dactivemq.username=... / -Dactivemq.password=...

3. ear/WEB-INF/jetty-env.xml: same change for the webapp-scoped
   ActiveMQConnectionFactory (jms/ConnectionFactory).

Default credentials are 'rhythmyx' / 'rhythmyx' (placeholder, not a
secret). Operators opening a network listener (adding a
<transportConnector>) MUST change the password and add a per-listener
user. The comment in activemq.xml points at this requirement.

This PR is built on top of #211 (the activemq.xml XSD-validity fixes);
once both merge, the broker should start cleanly, the in-VM connection
should authenticate, and the JMS listeners should reach steady state
without retries.

Refs #212

> Co-Authored by Mavis Mavis-Code using MiniMax-M3 with agent mavis.
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.

2 participants