TOMEE-4654 - Allow the component naming context to be made read-only - #2846
TOMEE-4654 - Allow the component naming context to be made read-only#2846jungm wants to merge 3 commits into
Conversation
The Enterprise Beans spec (10.4.4) and EE.5.3.4 require java:comp and its subcontexts to be read-only inside a deployed application: write attempts must not take effect. The IvmContext read-only machinery already existed but was gated behind openejb.forceReadOnlyAppNamingContext, which defaulted to false, so every deployed application received a fully writable ENC. Flip that default to true (retained as an explicit opt-out for backward compatibility) and extend the enforcement to the web and app contexts. Servlets and JSF managed beans resolve java:comp/java:module/java:app through the WebContext and AppContext rather than a BeanContext, so marking only the BeanContexts read-only left the web tier writable. Adds JavaCompReadOnlyTest, which deploys a real application and asserts that bind/rebind/rename/unbind/createSubcontext/destroySubcontext are all refused on java:comp and java:app, and inverts AppNamingReadOnlyTest, whose former testAppNamingContextWritableByDefault asserted the exact behaviour being fixed.
|
The underlying bug is real and worth fixing — the read-only machinery has been there since I can't approve as-is though — the marking happens at the wrong point in the lifecycle, and it Container-internal binds can now fail. I probed this directly in openejb-core: with the patch applied, after And the same modules never get marked. The flip side: Both problems have one shape of fix: record the read-only intent on the Other things:
|
… are started Review feedback on the first commit: marking the contexts at the end of createApplication is the wrong point in the lifecycle, and it cuts both ways. isSkip defers the ejb modules of an ear's web modules to the web app builders, which call initEjbs and startEjbs after createApplication has returned. Closing the application context in createApplication therefore made JndiBuilder's app/<module>/<bean> bindings fail with OperationNotSupportedException on that later pass, while the java:comp of exactly those modules was never closed at all - the spec violation survived for the beans living in an ear's web modules. Moving the marking to the end of startEjbs fixes both: the containers bind comp/EJBContext, comp/WebServiceContext and comp/TimerService into each bean enc while deploying, which happens there and not in initEjbs. The intent is recorded on the AppContext when the application is configured and applied once the deployments exist, so late modules are covered too. The shared application context is only closed once no further module can bind into it, tracked by a count of the late modules still to come. Also from the review: - Drop the WebContext loop. Neither TomcatWebAppBuilder nor LightweightWebAppBuilder stores an IvmContext or ContextHandler in WebContext.jndiEnc, so it never matched and was dead code. - Read the opt-out from appInfo.properties before the system property, as the other Assembler switches do, so one legacy application cannot force the whole container off the behaviour the specification requires. - Parse the opt-out with Boolean.parseBoolean so -D...=FALSE is honoured. - Invert EmbeddedTomEEContainerTest.testEjbCanCreateSubContextByDefault, which still asserted the pre-fix semantic, into a test that the write is refused. - Accept both refusal modes in the new tests instead of requiring OperationNotSupportedException, run deploy() inside the try/finally so a failure there cannot skip SystemInstance.reset(), and replace the tautological rename/destroySubcontext assertions.
|
Thanks — this was a genuinely useful review, and you were right on every point. Pushed in 5cf5d33. Timing. Moved as you suggested, but the end of The shared app context. Since Dead Opt-out. Now reads
Test nits. Full Agreed on the Arquillian point; the inverted test above is the real-container coverage, and I'm happy to add more if you'd like a specific EAR-with-WAR scenario. 🤖 Addressed by Claude Code |
Review feedback: enabling the read only component naming context for everyone is a behaviour change that would break the applications writing into their own naming context after deployment, so openejb.forceReadOnlyAppNamingContext goes back to being off by default and the TCK turns it on for its runs. The lifecycle work stays as it is: when the flag is set the contexts are still marked at the end of startEjbs, so the ear web modules deployed later by the web app builders are covered and the container's own binds all run first. Makes the constant public so the harness and tests outside assembler.classic can set it, opts JavaCompReadOnlyTest into the flag explicitly, and restores EmbeddedTomEEContainerTest.testEjbCanCreateSubContextByDefault to asserting the write succeeds.
|
Good call — done in 3c75c91. The lifecycle work from the last round stays: when the flag is set, the contexts are marked at the end of Full One consequence worth stating plainly: with the default off, TomEE still deviates from EE.5.3.4 / Enterprise Beans 10.4.4 out of the box, so the behaviour TOMEE-4654 reported is unchanged for anyone who doesn't set the flag. Happy to leave it here and revisit the default for a major release, or file a follow-up to track it — whichever you prefer. The matching tomee-tck change (setting the flag in the TomEE config and un-excluding the write tests) will be a separate PR there. 🤖 Addressed by Claude Code |
What
Adds working support for the read-only
java:compcomponent naming context that the Enterprise Beans spec (10.4.4) and EE.5.3.4 require, behindopenejb.forceReadOnlyAppNamingContext. The default stays writable, so this changes nothing for existing applications; the TCK turns the flag on for its runs.Why
The
IvmContextread-only enforcement has existed since d5b3b93 (2017) —checkReadOnly()throwsOperationNotSupportedExceptionandsetReadOnly()cascades through the name tree — but nothing ever turned it on, and turning it on at the obvious place did not work. This makes the switch actually usable.Per review discussion, enabling it by default is a behavioural change that would break applications writing into their own ENC after deployment, so it remains opt-in until that can be a release-wide change. TomEE therefore still deviates from the spec out of the box; this PR provides the mechanism and the TCK coverage rather than flipping the behaviour for everyone.
Changes
Assembler:openejb.forceReadOnlyAppNamingContextis read fromappInfo.propertiesfirst with the system property as fallback (asOPENEJB_TIMERS_ONand friends do), so it can be set per application or container-wide, and parsed withBoolean.parseBooleanso=FALSEis honoured. Defaultfalse.AppContextwhen the application is configured and applied at the end ofstartEjbs:isSkipdefers the EJB modules of an EAR's web modules to the web app builders, which callinitEjbs/startEjbsaftercreateApplicationhas returned. Marking increateApplicationmakesJndiBuilder'sapp/<module>/<bean>bindings fail withOperationNotSupportedExceptionon that later pass, while thejava:compof exactly those modules is never closed at all.comp/EJBContext,comp/WebServiceContextandcomp/TimerServiceinto each bean ENC fromSingletonInstanceManager.deploy()/StatelessInstanceManager.deploy(), which run instartEjbs— so marking at the end ofinitEjbsbreaks singleton and stateless deployment outright.AppContext: carries the read-only intent and the pending-late-module count.JavaCompReadOnlyTestopts into the flag, deploys a real application and asserts every write op is refused onjava:compandjava:app, that nothing written becomes observable, and that pre-existing bindings survive;AppNamingReadOnlyTestcovers the enabled and default paths plus the late-module deferral.Verification
openejb-corefull suite: 4096 tests, the only 6 failures are pre-existing security-test failures that reproduce on a cleanmain. (ConnectionFactoryTxTestfailed once with a null injectedConnectionFactoryand passed on a repeat full run plus 5 isolated runs;InjectionProcessorperforms no ENC writes, so read-only cannot affect injection — a pre-existing flake against the shared ActiveMQ broker.)enterprise-beans-30with the flag enabled: thenaming/contextwrite assertions pass in both the EJB and web (servlet / filtered-servlet / JSF) vehicles.Reviewer notes
apache/tomee-tck.WebContexthandling:WebContext.jndiEncholds anInitialContextor aWebInitialContextproxy, never anIvmContext/ContextHandler, so marking it would be a no-op.org.apache.naming.NamingContextinstead ofIvmContext, sojava:comp/envlists extracomp/moduleentries andclose()fails. Orthogonal to this change and not addressed here.🤖 Generated with Claude Code