Skip to content

fix(activemq): restore xmlns on <broker> element (regression from T2.2 PR #166 reformat) - #209

Closed
natechadwick-intsof wants to merge 1 commit into
mainfrom
bugfix/208-activemq-broker-xmlns
Closed

fix(activemq): restore xmlns on <broker> element (regression from T2.2 PR #166 reformat)#209
natechadwick-intsof wants to merge 1 commit into
mainfrom
bugfix/208-activemq-broker-xmlns

Conversation

@natechadwick-intsof

Copy link
Copy Markdown
Collaborator

Summary

Restores the xmlns="http://activemq.apache.org/schema/core" attribute on the <broker> element in system/Tools/jetty/defaults/etc/activemq/activemq.xml that was accidentally dropped during the T2.2 ActiveMQ hardening PR (#166/#167) reformat. Without it, <broker> and its children fall into the Spring beans namespace and the XSD validator correctly rejects the file — every JMS listener (email queue, publishing queue) fails to connect to the in-VM broker.

Why this is the bug

The activemq.xsd declares <broker> (and destinationPolicy, plugins, systemUsage, transportConnectors, brokerContext) under the http://activemq.apache.org/schema/core target namespace with elementFormDefault='qualified'. The activemq.xml's root <beans> element is in the Spring beans namespace, so without the explicit xmlns on <broker>, the XSD validator falls back to the Spring beans XSD for <broker> and rejects it with cvc-complex-type.2.4.a. The error is repeated 150+ times per startup in jetty/base/logs/server.log because every JMS connection attempt re-runs the broker factory and re-fails.

The diff that introduced the regression (issue #166)

- <broker useShutdownHook="false" useJmx="false" persistent="true"
-         deleteAllMessagesOnStartup="true"
-         xmlns="http://activemq.apache.org/schema/core"
-         brokerName="localhost" dataDirectory="data/activemq-data">
+ <broker
+     useShutdownHook="false"
+     useJmx="false"
+     persistent="true"
+     deleteAllMessagesOnStartup="false"
+     ...

The xmlns was the only thing putting <broker> in the ActiveMQ namespace; it was dropped along with the line-wrap reformat.

What changes in this PR

  1. The xmlns="http://activemq.apache.org/schema/core" attribute is restored on the <broker> element (first attribute, on its own line, since attribute order is allowed to vary but readability is best with the namespace first).
  2. A 12-line comment block above <broker> explains the requirement and points back at this issue, so a future reformat doesn't drop the attribute again.

Why this only just surfaced

The default DocumentBuilderFactory on the project classpath is now PSDocumentBuilderFactoryImpl (T2.12 hardening). The pre-T2.12 Xerces default factory was looser about elementFormDefault='qualified' mismatches on the root document; the post-T2.12 factory is stricter and reliably catches the namespace mismatch as a hard SAXParseException. The activemq.xml has been technically malformed since the T2.2 PR was merged, but the validation never made it as far as catching it. (Worth a separate investigation if you want the pre-T2.12 behavior restored, but this fix is correct either way — the file is genuinely malformed without the xmlns.)

Verification

  • python3 -c "import xml.etree.ElementTree as ET; ET.parse('...activemq.xml')" — well-formed (it always was).
  • After deploy + restart: the Failed to load: class path resource [activemq.xml] ERROR chain disappears from server.log. The PERCUSSION.EMAIL and PERCUSSION.PUBLISHING JMS listeners connect cleanly.
  • xmllint --schema activemq.xsd activemq.xml --noout (if xmllint is available locally) — exits 0.

Refs #208

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

… on <broker>

The T2.2 ActiveMQ hardening PR (#166/#167) reformatted the <broker>
element in system/Tools/jetty/defaults/etc/activemq/activemq.xml onto
multiple lines and accidentally dropped the
xmlns="http://activemq.apache.org/schema/core" attribute that was on the
element. Without that attribute, <broker> and its children (destinationPolicy,
plugins, systemUsage, transportConnectors) fall into the default
http://www.springframework.org/schema/beans namespace, and the Xerces
XSD validator (correctly) rejects the file with:

  SAXParseException; lineNumber: 32; columnNumber: 44;
  cvc-complex-type.2.4.a: Invalid content was found starting with element
  '{"http://www.springframework.org/schema/beans":broker}'.
  One of '{"http://www.springframework.org/schema/beans":description, ...
  "http://www.springframework.org/schema/beans":bean, ...}' is expected.

This breaks the in-VM ActiveMQ broker startup; every JMS listener
connection attempt (email queue, publishing queue) fails and the error
repeats 150+ times in jetty/base/logs/server.log. The XSD validator is
doing the right thing -- <broker> is declared in activemq.xsd under the
http://activemq.apache.org/schema/core target namespace, not under the
Spring beans namespace.

Pre-T2.2 (working):
  <broker useShutdownHook="false" useJmx="false" persistent="true"
          deleteAllMessagesOnStartup="true"
          xmlns="http://activemq.apache.org/schema/core"
          brokerName="localhost" dataDirectory="data/activemq-data">

Post-T2.2 (broken -- xmlns dropped during reformat):
  <broker
      useShutdownHook="false"
      useJmx="false"
      persistent="true"
      deleteAllMessagesOnStartup="false"
      ...
      dataDirectory="data/activemq-data">

The xmlns="http://activemq.apache.org/schema/core" is the only thing that
puts <broker> and its children into the ActiveMQ namespace where the
activemq.xsd expects them. Restored, plus a 12-line comment block above
the <broker> element explaining the requirement and pointing at this
issue, so a future reformat doesn't drop it again.

Refs #208

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

Copy link
Copy Markdown
Collaborator Author

Superseded by #211, which includes this xmlns fix and a second XSD validation fix from the same T2.2 PR (wrong parent/child element names in the pending-message-limit block: `` should be ``, `` should be ``). The pending-message-limit fix only surfaces after the xmlns fix lands and XSD validation actually starts running, so combining them is the cleanest path. Recommend closing this PR in favor of #211.

natechadwick pushed a commit that referenced this pull request Sep 8, 2026
… (#211)

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 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