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` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
