You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by "ASF GitHub Bot (Jira)" <ji...@apache.org> on 2026/09/25 11:52:00 UTC

[jira] [Work logged] (TOMEE-4712) MDB endpoints are activated before the application's other EJBs are started

     [ https://issues.apache.org/jira/browse/TOMEE-4712?focusedWorklogId=1043974&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1043974 ]

ASF GitHub Bot logged work on TOMEE-4712:
-----------------------------------------

                Author: ASF GitHub Bot
            Created on: 25/Sep/26 11:51
            Start Date: 25/Sep/26 11:51
    Worklog Time Spent: 10m 
      Work Description: jungm opened a new pull request, #2951:
URL: https://github.com/apache/tomee/pull/2951

   ## What
   
   Fixes [TOMEE-4712](https://issues.apache.org/jira/browse/TOMEE-4712): an MDB receives messages before the other EJBs of its application are started, and calls into an injected `@Stateless` bean fail with
   
   ```
   java.lang.NullPointerException: Cannot invoke "org.apache.openejb.core.stateless.StatelessInstanceManager$Data.poolPop()" because "data" is null
   ```
   
   Reported on the [users list](https://lists.apache.org/thread/pg3vv6xr9yd19wowj6lg31b4w4w19bnn) against 10.2.0, for messages left on a topic when the server was stopped.
   
   ## Why
   
   `Assembler.startEjbs()` works in two passes: `container.deploy()` for every bean, then `container.start()` for every bean. `MdbContainer.deploy()` (and `MdbInstanceManager.deploy()` for `Pool=true`) called `resourceAdapter.endpointActivation(...)` directly, so the resource adapter could deliver during the deploy pass. At that point:
   
   - stateless beans have no instance pool yet: `StatelessInstanceManager.deploy()`, which sets the bean's container data, runs from `StatelessContainer.start()`
   - `@Startup` singletons are not initialized yet: that happens in `SingletonContainer.start()`
   
   `Assembler.sort()` already moves MDBs to the end so the beans they reference are available first, but that ordering only helps if activation happens in the start pass.
   
   Delivering before `@Startup` singletons are initialized also contradicts Jakarta Enterprise Beans 4.0 Core, [4.8.1 Singleton Session Bean Initialization](https://jakarta.ee/specifications/enterprise-beans/4.0/jakarta-enterprise-beans-spec-core-4.0.html#singleton-session-bean-initialization) ("The container must initialize all such startup-time singleton session beans before any external client requests ... are delivered to any enterprise bean components in the application"). Jakarta Connectors 2.1, [14.4.4](https://jakarta.ee/specifications/connectors/2.1/jakarta-connectors-spec-2.1.html#a2765), explicitly allows a resource adapter to deliver during `endpointActivation`, so this is not ActiveMQ-specific.
   
   ## The fix
   
   - `MdbContainer` and `MdbInstanceManager` still create the activation context and JMX control in `deploy()`, but activate the endpoint in `start()`. `MdbContainer.current()` stays available to the resource adapter during activation.
   - `MdbActiveOnStartup`/`DeliveryActive=false` keep working. The check both containers duplicated is now `BaseMdbContainer.isActiveOnStartup()`.
   - Undeploy only deactivates a started endpoint already, so a bean that fails between deploy and start is still cleaned up.
   - For `Pool=true`, the endpoint is now also activated after the MDB's own instance pool is filled and started.
   
   ## Testing
   
   New `MdbActivationOrderTest`, parameterized over `Pool=false`/`Pool=true`: a resource adapter delivers a pending message inside `endpointActivation`, and the MDB calls an injected `@Stateless` bean.
   
   - **Without the fix:** both variants fail with the NPE above
   - **With the fix:** both pass
   - Full `openejb-core` build: `Tests run: 4113, Failures: 0, Errors: 0, Skipped: 4`
   




Issue Time Tracking
-------------------

            Worklog Id:     (was: 1043974)
    Remaining Estimate: 0h
            Time Spent: 10m

> MDB endpoints are activated before the application's other EJBs are started
> ---------------------------------------------------------------------------
>
>                 Key: TOMEE-4712
>                 URL: https://issues.apache.org/jira/browse/TOMEE-4712
>             Project: TomEE
>          Issue Type: Bug
>    Affects Versions: 11.0.0-M1, 10.2.0
>            Reporter: Markus Jung
>            Assignee: Markus Jung
>            Priority: Major
>             Fix For: 11.0.0, 10.3.0
>
>          Time Spent: 10m
>  Remaining Estimate: 0h
>
> {{Assembler.startEjbs()}} deploys all beans of an application first and starts them afterwards. {{MdbContainer.deploy()}} and {{MdbInstanceManager.deploy()}} (for {{Pool=true}}) activate the message endpoint right away, so the resource adapter can deliver messages during the deploy pass. The other beans of the application are not started yet at that point: stateless beans get their instance pool in {{StatelessContainer.start()}}, {{@Startup}} singletons are initialized in {{SingletonContainer.start()}}.
> Messages that are already waiting on the destination (for example because the server was stopped with unprocessed messages) are therefore delivered to an MDB whose injected stateless bean has no pool yet:
> {code}java.lang.NullPointerException: Cannot invoke "org.apache.openejb.core.stateless.StatelessInstanceManager$Data.poolPop()" because "data" is null
>     at org.apache.openejb.core.stateless.StatelessInstanceManager.getInstance(StatelessInstanceManager.java:218)
>     at org.apache.openejb.core.stateless.StatelessContainer.invoke(StatelessContainer.java:204)
>     ...
>     at org.apache.openejb.core.mdb.MdbContainer$MdbActivationContext.start(MdbContainer.java:689)
>     at org.apache.openejb.core.mdb.MdbContainer.deploy(MdbContainer.java:251)
>     at org.apache.openejb.assembler.classic.Assembler.startEjbs(Assembler.java:1690)
> {code}
> It also lets messages reach the application before its {{@Startup}} singletons are initialized, which Jakarta Enterprise Beans 4.0 Core, [4.8.1 Singleton Session Bean Initialization|https://jakarta.ee/specifications/enterprise-beans/4.0/jakarta-enterprise-beans-spec-core-4.0.html#singleton-session-bean-initialization] forbids:
> bq. The container must initialize all such startup-time singleton session beans before any external client requests (that is, client requests originating outside of the application) are delivered to any enterprise bean components in the application.
> Jakarta Connectors 2.1, [14.4.4 Application Server|https://jakarta.ee/specifications/connectors/2.1/jakarta-connectors-spec-2.1.html#a2765] explicitly allows a resource adapter to deliver during {{endpointActivation}}:
> bq. Note, a resource adapter may attempt to deliver messages during the endpointActivation method call.
> Reported on the [users list|https://lists.apache.org/thread/pg3vv6xr9yd19wowj6lg31b4w4w19bnn] against TomEE 10.2.0: an MDB with an injected {{@Stateless}} bean logs these NPEs on startup while messages from before the shutdown are pending on its topic.
> Fix: activate the endpoint in {{start()}} of both MDB containers instead of {{deploy()}}. {{Assembler}} sorts MDBs to the end of the start pass, so every session bean of the application is started before the first message is delivered. {{MdbActiveOnStartup}}/{{DeliveryActive=false}} keep working as before.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)