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

Reply via email to