This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 1c33320082ee78f9bb936aa38638257f0de2191f
Author: opencode <[email protected]>
AuthorDate: Fri Nov 6 17:56:09 2026 +0100

    Complete OWB test coverage for lifecycle, instance manager and EL
    
    Add request/session listener lifecycle and injection coverage, dynamic 
context-listener deployment, all InstanceManager creation paths, security 
ThreadLocal cleanup, expanded JSP/EL tests and classloader leak checks. 
Document the EL method-invocation limitation.
---
 modules/owb/README.md                              | 21 +++--
 modules/owb/pom.xml                                |  2 +
 .../web/tomcat/OpenWebBeansClassLoaderLeakIT.java  | 95 ++++++++++++++++++++++
 .../web/tomcat/OpenWebBeansInstanceManagerIT.java  | 58 +++++++++++++
 .../webbeans/web/tomcat/OpenWebBeansJspIT.java     | 13 ++-
 .../web/tomcat/OpenWebBeansSecurityFilterTest.java | 67 +++++++++++++++
 .../web/tomcat/OpenWebBeansSecurityValveTest.java  | 67 +++++++++++++++
 .../tomcat/OpenWebBeansTomcatIntegrationIT.java    | 27 +++++-
 .../apache/webbeans/web/tomcat/OwbTestServer.java  | 68 ++++++++++++----
 .../{jsp/index.jsp => instance/WEB-INF/beans.xml}  | 13 +--
 .../web/tomcat/testapp/InstanceProbe.java}         | 27 +++---
 .../web/tomcat/testapp/InstanceProbeServlet.java   | 79 ++++++++++++++++++
 .../webbeans/web/tomcat/testapp/ProbeGreeting.java | 27 ++++++
 .../jsp/{index.jsp => WEB-INF/tags/greeting.tag}   |  6 +-
 .../test/webapp/jsp/{index.jsp => included.jsp}    |  5 +-
 modules/owb/src/test/webapp/jsp/index.jsp          |  9 +-
 .../webbeans/web/tomcat/testapp/ElServlet.java}    | 50 ++++--------
 .../web/tomcat/testapp/MethodGreeting.java         | 29 +++++++
 .../web/tomcat/testapp/RequestGreeting.java        | 33 ++++++++
 .../tomcat/testapp/LifecycleContextListener.java   | 14 +++-
 .../web/tomcat/testapp/LifecycleFilter.java        |  6 ++
 ...extListener.java => LifecycleMarkerWriter.java} | 23 ++----
 ...Listener.java => LifecycleRequestListener.java} | 31 +++----
 .../web/tomcat/testapp/LifecycleServlet.java       |  6 +-
 ...Listener.java => LifecycleSessionListener.java} | 31 +++----
 webapps/docs/cdi.xml                               |  5 ++
 26 files changed, 672 insertions(+), 140 deletions(-)

diff --git a/modules/owb/README.md b/modules/owb/README.md
index a228912fc8..e527163b64 100644
--- a/modules/owb/README.md
+++ b/modules/owb/README.md
@@ -139,12 +139,16 @@ provided through the test/common classpath, matching the 
production
 |---|---|
 | `TomcatPluginTest` | Servlet spec class handling, managed-bean rejection, 
injection support and security service registration |
 | `OpenWebBeansInstanceManagerTest` | Delegation for all `InstanceManager` 
creation variants and destruction fallback |
+| `OpenWebBeansSecurityFilterTest` | Filter principal visibility and 
ThreadLocal cleanup |
+| `OpenWebBeansSecurityValveTest` | Valve principal visibility and ThreadLocal 
cleanup |
 | `OpenWebBeansCdi41IT` | CDI injection, request/session scope, 
`isMatchingBean`, `isMatchingEvent`, `getContexts`, interceptor bindings, 
method invoker |
-| `OpenWebBeansTomcatIntegrationIT` | Server/context listener modes, 
`startWithoutBeansXml` positive and negative behavior, alternate `beans.xml` 
location, security valve configuration, dynamic deployment, 
filter/listener/servlet field injection and lifecycle callbacks |
+| `OpenWebBeansTomcatIntegrationIT` | Server/context listener modes, 
`startWithoutBeansXml` positive and negative behavior, alternate `beans.xml` 
location, security valve configuration, dynamic deployment with both listener 
modes, filter/listener/servlet field injection and lifecycle callbacks |
 | `OpenWebBeansSecurityIT` | BASIC authentication, `@Inject Principal`, 
security valve principal, principal proxy modes and custom proxy APIs |
 | `OpenWebBeansSecurityFilterIT` | Webapp-level `OpenWebBeansSecurityFilter` |
-| `OpenWebBeansJspIT` | JSP/EL resolution through OWB |
+| `OpenWebBeansInstanceManagerIT` | End-to-end injection through all 
`InstanceManager` creation paths and context classloader restoration |
+| `OpenWebBeansJspIT` | JSP property/method/include/tag-file EL, 
request-scoped EL and programmatic EL resolver access |
 | `OpenWebBeansRedeployIT` | Multiple webapps, classloader isolation, context 
restart, `@PreDestroy`, listener registration |
+| `OpenWebBeansClassLoaderLeakIT` | Enabled leak checks, no reported 
ThreadLocal/RMI leaks, context restart |
 
 ## Adding a test
 
@@ -177,9 +181,13 @@ try (OwbTestServer server = OwbTestServer.start(webapp,
   so no failing gate test is included.
 - `ELAwareBeanManager` is not covered. OpenWebBeans provides the core
   `BeanManager`, and the supplemental CDI EL API is not part of this module.
-- Classloader garbage-collection leak detection is not asserted. The redeploy
-  tests verify deterministic behavior: pre-destroy callbacks, separate
-  contexts, no duplicate listener registration and successful restart.
+- EL method invocation against a normal-scoped CDI proxy bean is not covered
+  because OpenWebBeans reports `MethodNotFoundException` for that case. Use
+  property access or a dependent bean for method invocation.
+- Classloader garbage-collection leak detection is not asserted. The
+  redeploy tests verify deterministic behavior, and
+  `OpenWebBeansClassLoaderLeakIT` enables Tomcat's leak checks and asserts
+  that no ThreadLocal/RMI leak warnings are reported during context shutdown.
 
 ## Troubleshooting
 
@@ -190,5 +198,8 @@ try (OwbTestServer server = OwbTestServer.start(webapp,
 - **Tests run against the wrong classes**: check the Failsafe
   `classesDirectory`, `additionalClasspathElements` and
   `classpathDependencyExcludes` settings.
+- **Classloader leak checks**: `OpenWebBeansClassLoaderLeakIT` enables the
+  Tomcat leak checks and relies on the `--add-opens` options in the Failsafe
+  `argLine`.
 - **Port or directory conflicts**: the tests use port `0` and JUnit temporary
   directories; do not hard-code either in new tests.
diff --git a/modules/owb/pom.xml b/modules/owb/pom.xml
index 32d1a7ce8a..000ae41d9d 100644
--- a/modules/owb/pom.xml
+++ b/modules/owb/pom.xml
@@ -223,6 +223,8 @@
                     </execution>
                 </executions>
                 <configuration>
+                    <!-- Required by the optional classloader leak checks. -->
+                    <argLine>--add-opens=java.base/java.lang=ALL-UNNAMED 
--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED</argLine>
                     <!-- Test the shaded JAR rather than the unshaded classes 
-->
                     
<classesDirectory>${project.build.directory}/empty-classes</classesDirectory>
                     <additionalClasspathElements>
diff --git 
a/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansClassLoaderLeakIT.java
 
b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansClassLoaderLeakIT.java
new file mode 100644
index 0000000000..fa48c78e67
--- /dev/null
+++ 
b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansClassLoaderLeakIT.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.webbeans.web.tomcat;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.net.http.HttpClient;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.webbeans.web.tomcat.OwbTestServer.Deployment;
+import org.apache.webbeans.web.tomcat.OwbTestServer.ListenerMode;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+class OpenWebBeansClassLoaderLeakIT {
+
+    private static final String CLASSLOADER_LOGGER = 
"org.apache.catalina.loader.WebappClassLoaderBase";
+
+    @TempDir
+    Path tempDir;
+
+    @Test
+    void contextStopDoesNotReportClassLoaderLeaks() throws Exception {
+        Logger logger = Logger.getLogger(CLASSLOADER_LOGGER);
+        List<String> messages = new CopyOnWriteArrayList<>();
+        Level previousLevel = logger.getLevel();
+        Handler handler = new Handler() {
+            @Override
+            public void publish(LogRecord record) {
+                messages.add(record.getMessage());
+            }
+
+            @Override
+            public void flush() {
+            }
+
+            @Override
+            public void close() {
+            }
+        };
+        logger.addHandler(handler);
+        logger.setLevel(Level.ALL);
+        try {
+            Path webapp = new WebAppBuilder(tempDir.resolve("leak"), 
"lifecycle")
+                    .build(OwbTestSupport.shadedJar());
+            try (OwbTestServer server = OwbTestServer.start(
+                    List.of(new Deployment("/owb-leak", webapp)), 
ListenerMode.SERVER, false, true, false, true,
+                    null)) {
+                StandardContext context = (StandardContext) 
server.context("/owb-leak");
+                assertTrue(context.getClearReferencesThreadLocals());
+                assertTrue(context.getClearReferencesRmiTargets());
+
+                HttpClient client = OwbTestSupport.newClient();
+                OwbTestSupport.get(client, 
server.baseUri("/owb-leak").resolve("lifecycle"));
+
+                server.stopContext("/owb-leak");
+                
assertTrue(messages.stream().noneMatch(OpenWebBeansClassLoaderLeakIT::isLeakMessage),
+                        messages.toString());
+
+                server.startContext("/owb-leak");
+                OwbTestSupport.get(client, 
server.baseUri("/owb-leak").resolve("lifecycle"));
+            }
+        } finally {
+            logger.removeHandler(handler);
+            logger.setLevel(previousLevel);
+        }
+    }
+
+    private static boolean isLeakMessage(String message) {
+        String lower = message.toLowerCase(Locale.ROOT);
+        return lower.contains("threadlocal") || lower.contains("rmi target") 
|| lower.contains("memory leak");
+    }
+}
diff --git 
a/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansInstanceManagerIT.java
 
b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansInstanceManagerIT.java
new file mode 100644
index 0000000000..59de4a8092
--- /dev/null
+++ 
b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansInstanceManagerIT.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.webbeans.web.tomcat;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.net.http.HttpClient;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.apache.webbeans.web.tomcat.OwbTestServer.ListenerMode;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+class OpenWebBeansInstanceManagerIT {
+
+    @TempDir
+    Path tempDir;
+
+    @Test
+    void allInstanceManagerPathsInject() throws Exception {
+        Path markerDirectory = tempDir.resolve("markers");
+        Files.createDirectories(markerDirectory);
+        String previousMarkerDirectory = 
System.getProperty("owb.test.marker.dir");
+        System.setProperty("owb.test.marker.dir", markerDirectory.toString());
+        try {
+            Path webapp = new WebAppBuilder(tempDir.resolve("instance"), 
"instance")
+                    .build(OwbTestSupport.shadedJar());
+            try (OwbTestServer server = OwbTestServer.start(webapp, 
ListenerMode.SERVER, false, true)) {
+                HttpClient client = OwbTestSupport.newClient();
+                
assertEquals("class=injected,string=injected,stringLoader=injected,object=injected,context=restored",
+                        OwbTestSupport.get(client, 
server.baseUri().resolve("instance-probe")));
+                OwbTestSupport.assertMarker(markerDirectory, 
"probePostConstruct.marker");
+                OwbTestSupport.assertMarker(markerDirectory, 
"probePreDestroy.marker");
+            }
+        } finally {
+            if (previousMarkerDirectory == null) {
+                System.clearProperty("owb.test.marker.dir");
+            } else {
+                System.setProperty("owb.test.marker.dir", 
previousMarkerDirectory);
+            }
+        }
+    }
+}
diff --git 
a/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansJspIT.java
 
b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansJspIT.java
index 3824979aa2..90c452c7ff 100644
--- 
a/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansJspIT.java
+++ 
b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansJspIT.java
@@ -17,6 +17,7 @@
 package org.apache.webbeans.web.tomcat;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.net.http.HttpClient;
@@ -42,7 +43,17 @@ class OpenWebBeansJspIT {
             HttpResponse<String> response = OwbTestSupport.getResponse(client, 
server.baseUri().resolve("index.jsp"));
             assertEquals(200, response.statusCode(), response.body());
             
assertTrue(response.headers().firstValue("Content-Type").orElse("").startsWith("text/html"));
-            assertTrue(response.body().contains("hello-owb-4.1.1"), 
response.body());
+            String first = response.body();
+            assertTrue(first.contains("property:hello-owb-4.1.1"), first);
+            assertTrue(first.contains("method:hello-owb-4.1.1"), first);
+            assertTrue(first.contains("included:hello-owb-4.1.1"), first);
+            assertTrue(first.contains("tag:hello-owb-4.1.1"), first);
+            assertTrue(first.contains("request:request:"), first);
+
+            String second = OwbTestSupport.get(client, 
server.baseUri().resolve("index.jsp"));
+            assertNotEquals(first, second, "Request scoped EL value was not 
recreated");
+
+            assertEquals("hello-owb-4.1.1", OwbTestSupport.get(client, 
server.baseUri().resolve("el")));
         }
     }
 }
diff --git 
a/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansSecurityFilterTest.java
 
b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansSecurityFilterTest.java
new file mode 100644
index 0000000000..54cd6aeb55
--- /dev/null
+++ 
b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansSecurityFilterTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.webbeans.web.tomcat;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import java.lang.reflect.Proxy;
+import java.security.Principal;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.http.HttpServletRequest;
+import org.junit.jupiter.api.Test;
+
+class OpenWebBeansSecurityFilterTest {
+
+    @Test
+    void principalIsVisibleDuringChainAndClearedAfterwards() throws Exception {
+        Principal principal = () -> "testuser";
+        HttpServletRequest request = request(principal);
+
+        FilterChain chain = (servletRequest, servletResponse) ->
+                assertEquals(principal, 
OpenWebBeansSecurityFilter.getPrincipal());
+
+        new OpenWebBeansSecurityFilter().doFilter(request, null, chain);
+
+        assertNull(OpenWebBeansSecurityFilter.getPrincipal());
+    }
+
+    @Test
+    void nullPrincipalIsClearedAfterwards() throws Exception {
+        HttpServletRequest request = request(null);
+
+        FilterChain chain = (servletRequest, servletResponse) ->
+                assertNull(OpenWebBeansSecurityFilter.getPrincipal());
+
+        new OpenWebBeansSecurityFilter().doFilter(request, null, chain);
+
+        assertNull(OpenWebBeansSecurityFilter.getPrincipal());
+    }
+
+    private static HttpServletRequest request(Principal principal) {
+        return (HttpServletRequest) Proxy.newProxyInstance(
+                OpenWebBeansSecurityFilterTest.class.getClassLoader(),
+                new Class<?>[] { HttpServletRequest.class },
+                (proxy, method, args) -> {
+                    if ("getUserPrincipal".equals(method.getName())) {
+                        return principal;
+                    }
+                    throw new UnsupportedOperationException(method.getName());
+                });
+    }
+}
diff --git 
a/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansSecurityValveTest.java
 
b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansSecurityValveTest.java
new file mode 100644
index 0000000000..ed46d56640
--- /dev/null
+++ 
b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansSecurityValveTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.webbeans.web.tomcat;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import java.security.Principal;
+
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.valves.ValveBase;
+import org.junit.jupiter.api.Test;
+
+class OpenWebBeansSecurityValveTest {
+
+    @Test
+    void principalIsVisibleDuringNextValveAndClearedAfterwards() throws 
Exception {
+        Principal principal = () -> "testuser";
+        OpenWebBeansSecurityValve valve = new OpenWebBeansSecurityValve();
+        valve.setNext(new ValveBase() {
+            @Override
+            public void invoke(Request request, Response response) {
+                assertEquals(principal, 
OpenWebBeansSecurityValve.getPrincipal());
+            }
+        });
+
+        valve.invoke(request(principal), new Response(new 
org.apache.coyote.Response()));
+
+        assertNull(OpenWebBeansSecurityValve.getPrincipal());
+    }
+
+    @Test
+    void nullPrincipalIsClearedAfterwards() throws Exception {
+        OpenWebBeansSecurityValve valve = new OpenWebBeansSecurityValve();
+        valve.setNext(new ValveBase() {
+            @Override
+            public void invoke(Request request, Response response) {
+                assertNull(OpenWebBeansSecurityValve.getPrincipal());
+            }
+        });
+
+        valve.invoke(request(null), new Response(new 
org.apache.coyote.Response()));
+
+        assertNull(OpenWebBeansSecurityValve.getPrincipal());
+    }
+
+    private static Request request(Principal principal) {
+        Request request = new Request(null, new org.apache.coyote.Request());
+        request.setUserPrincipal(principal);
+        return request;
+    }
+}
diff --git 
a/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansTomcatIntegrationIT.java
 
b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansTomcatIntegrationIT.java
index 62b2147b19..6af60db6c4 100644
--- 
a/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansTomcatIntegrationIT.java
+++ 
b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansTomcatIntegrationIT.java
@@ -129,6 +129,23 @@ class OpenWebBeansTomcatIntegrationIT {
         }
     }
 
+    @Test
+    void dynamicContextDeploymentWithContextListener() throws Exception {
+        Path shadedJar = OwbTestSupport.shadedJar();
+        Path initial = new 
WebAppBuilder(tempDir.resolve("dynamic-context-initial"), 
"cdi41").build(shadedJar);
+        Path dynamic = new 
WebAppBuilder(tempDir.resolve("dynamic-context-app"), 
"multi/one").build(shadedJar);
+        try (OwbTestServer server = OwbTestServer.start(initial, 
ListenerMode.CONTEXT, false, true)) {
+            assertHello(server);
+
+            server.deploy("/owb-dynamic-context", dynamic);
+
+            HttpClient client = OwbTestSupport.newClient();
+            assertEquals("one", OwbTestSupport.get(client,
+                    server.baseUri("/owb-dynamic-context").resolve("value")));
+            assertHello(server);
+        }
+    }
+
     @Test
     void filterListenerAndServletInjection() throws Exception {
         Path markerDirectory = tempDir.resolve("markers");
@@ -142,14 +159,20 @@ class OpenWebBeansTomcatIntegrationIT {
                 HttpClient client = OwbTestSupport.newClient();
                 HttpResponse<String> response = 
OwbTestSupport.getResponse(client, server.baseUri().resolve("lifecycle"));
                 assertEquals(200, response.statusCode(), response.body());
-                
assertEquals("lifecycle-owb-4.1.1|lifecycle-owb-4.1.1|lifecycle-owb-4.1.1",
-                        response.body().strip());
+                
assertEquals("lifecycle-owb-4.1.1|lifecycle-owb-4.1.1|lifecycle-owb-4.1.1|lifecycle-owb-4.1.1|"
+                        + "lifecycle-owb-4.1.1", response.body().strip());
                 assertEquals("lifecycle-owb-4.1.1", 
response.headers().firstValue("X-Owb-Greeting").orElse(null));
                 OwbTestSupport.assertMarker(markerDirectory, 
"postConstruct.marker");
+                OwbTestSupport.assertMarker(markerDirectory, 
"filterPostConstruct.marker");
+                OwbTestSupport.assertMarker(markerDirectory, 
"listenerPostConstruct.marker");
+                OwbTestSupport.assertMarker(markerDirectory, 
"requestListenerPostConstruct.marker");
+                OwbTestSupport.assertMarker(markerDirectory, 
"sessionListenerPostConstruct.marker");
             }
             OwbTestSupport.assertMarker(markerDirectory, "preDestroy.marker");
             OwbTestSupport.assertMarker(markerDirectory, 
"filterPreDestroy.marker");
             OwbTestSupport.assertMarker(markerDirectory, 
"listenerPreDestroy.marker");
+            OwbTestSupport.assertMarker(markerDirectory, 
"requestListenerPreDestroy.marker");
+            OwbTestSupport.assertMarker(markerDirectory, 
"sessionListenerPreDestroy.marker");
         } finally {
             if (previousMarkerDirectory == null) {
                 System.clearProperty("owb.test.marker.dir");
diff --git 
a/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OwbTestServer.java 
b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OwbTestServer.java
index 7b607afd7d..f0832def5d 100644
--- 
a/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OwbTestServer.java
+++ 
b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OwbTestServer.java
@@ -25,7 +25,10 @@ import java.util.Map;
 import java.util.function.Consumer;
 
 import org.apache.catalina.Context;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
 import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.startup.ContextConfig;
 import org.apache.catalina.startup.Tomcat;
 
 /**
@@ -47,16 +50,19 @@ final class OwbTestServer implements AutoCloseable {
     private final ListenerMode listenerMode;
     private final boolean startWithoutBeansXml;
     private final boolean addSecurityValve;
+    private final boolean enableLeakChecks;
     private final int port;
 
     private OwbTestServer(Tomcat tomcat, Map<String, Context> contexts, 
Map<String, URI> baseUris,
-            ListenerMode listenerMode, boolean startWithoutBeansXml, boolean 
addSecurityValve, int port) {
+            ListenerMode listenerMode, boolean startWithoutBeansXml, boolean 
addSecurityValve,
+            boolean enableLeakChecks, int port) {
         this.tomcat = tomcat;
         this.contexts = contexts;
         this.baseUris = baseUris;
         this.listenerMode = listenerMode;
         this.startWithoutBeansXml = startWithoutBeansXml;
         this.addSecurityValve = addSecurityValve;
+        this.enableLeakChecks = enableLeakChecks;
         this.port = port;
     }
 
@@ -81,6 +87,13 @@ final class OwbTestServer implements AutoCloseable {
 
     static OwbTestServer start(List<Deployment> deployments, ListenerMode 
mode, boolean startWithoutBeansXml,
             boolean addSecurityValve, boolean useDefaultWebXml, 
Consumer<Tomcat> configurer) throws Exception {
+        return start(deployments, mode, startWithoutBeansXml, 
addSecurityValve, useDefaultWebXml, false,
+                configurer);
+    }
+
+    static OwbTestServer start(List<Deployment> deployments, ListenerMode 
mode, boolean startWithoutBeansXml,
+            boolean addSecurityValve, boolean useDefaultWebXml, boolean 
enableLeakChecks,
+            Consumer<Tomcat> configurer) throws Exception {
         Path base = 
Files.createTempDirectory(deployments.get(0).webapp().getParent(), "tomcat-");
 
         Tomcat tomcat = new Tomcat();
@@ -99,8 +112,8 @@ final class OwbTestServer implements AutoCloseable {
 
         Map<String, Context> contexts = new LinkedHashMap<>();
         for (Deployment deployment : deployments) {
-            Context context = tomcat.addWebapp(deployment.contextPath(), 
deployment.webapp().toString());
-            configureContext(context, mode, startWithoutBeansXml, 
addSecurityValve);
+            Context context = addWebapp(tomcat, deployment.contextPath(), 
deployment.webapp(), mode,
+                    startWithoutBeansXml, addSecurityValve, enableLeakChecks);
             contexts.put(deployment.contextPath(), context);
         }
 
@@ -123,12 +136,13 @@ final class OwbTestServer implements AutoCloseable {
         for (String contextPath : contexts.keySet()) {
             baseUris.put(contextPath, URI.create("http://127.0.0.1:"; + port + 
contextPath + "/"));
         }
-        return new OwbTestServer(tomcat, contexts, baseUris, mode, 
startWithoutBeansXml, addSecurityValve, port);
+        return new OwbTestServer(tomcat, contexts, baseUris, mode, 
startWithoutBeansXml, addSecurityValve,
+                enableLeakChecks, port);
     }
 
     Context deploy(String contextPath, Path webapp) throws Exception {
-        Context context = tomcat.addWebapp(contextPath, webapp.toString());
-        configureContext(context, listenerMode, startWithoutBeansXml, 
addSecurityValve);
+        Context context = addWebapp(tomcat, contextPath, webapp, listenerMode, 
startWithoutBeansXml,
+                addSecurityValve, enableLeakChecks);
         if (!context.getState().isAvailable()) {
             context.start();
         }
@@ -174,19 +188,43 @@ final class OwbTestServer implements AutoCloseable {
         }
     }
 
-    private static void configureContext(Context context, ListenerMode mode, 
boolean startWithoutBeansXml,
-            boolean addSecurityValve) {
-        if (context instanceof StandardContext standardContext) {
-            // These checks require --add-opens for java.lang and java.rmi.
-            // They are not relevant to the module integration tests.
-            standardContext.setClearReferencesThreadLocals(false);
-            standardContext.setClearReferencesRmiTargets(false);
-        }
+    private static Context addWebapp(Tomcat tomcat, String contextPath, Path 
webapp, ListenerMode mode,
+            boolean startWithoutBeansXml, boolean addSecurityValve, boolean 
enableLeakChecks) {
+        Context context;
         if (mode == ListenerMode.CONTEXT) {
             OpenWebBeansContextLifecycleListener listener = new 
OpenWebBeansContextLifecycleListener();
             listener.setStartWithoutBeansXml(startWithoutBeansXml);
             listener.setAddSecurityValve(addSecurityValve);
-            context.addLifecycleListener(listener);
+            // Register the listener before the context starts so dynamic
+            // deployments also receive the CONFIGURE_START event.
+            context = tomcat.addWebapp(tomcat.getHost(), contextPath, 
webapp.toString(),
+                    new OwbContextConfig(listener));
+        } else {
+            context = tomcat.addWebapp(contextPath, webapp.toString());
+        }
+        if (!enableLeakChecks && context instanceof StandardContext 
standardContext) {
+            // These checks require --add-opens for java.lang and java.rmi.
+            // They are only enabled by the dedicated leak test.
+            standardContext.setClearReferencesThreadLocals(false);
+            standardContext.setClearReferencesRmiTargets(false);
+        }
+        return context;
+    }
+
+    private static final class OwbContextConfig extends ContextConfig {
+
+        private final OpenWebBeansContextLifecycleListener listener;
+
+        private OwbContextConfig(OpenWebBeansContextLifecycleListener 
listener) {
+            this.listener = listener;
+        }
+
+        @Override
+        public void lifecycleEvent(LifecycleEvent event) {
+            super.lifecycleEvent(event);
+            if (Lifecycle.CONFIGURE_START_EVENT.equals(event.getType())) {
+                listener.lifecycleEvent(event);
+            }
         }
     }
 
diff --git a/modules/owb/src/test/webapp/jsp/index.jsp 
b/modules/owb/src/test/webapp/instance/WEB-INF/beans.xml
similarity index 72%
copy from modules/owb/src/test/webapp/jsp/index.jsp
copy to modules/owb/src/test/webapp/instance/WEB-INF/beans.xml
index 21e1a03c3b..abc684f5de 100644
--- a/modules/owb/src/test/webapp/jsp/index.jsp
+++ b/modules/owb/src/test/webapp/instance/WEB-INF/beans.xml
@@ -1,4 +1,4 @@
-<%--
+<!--
   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
@@ -13,8 +13,9 @@
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
---%>
-<%@ page contentType="text/html; charset=UTF-8" %>
-<html>
-<body>${greeting.message}</body>
-</html>
+-->
+<beans xmlns="https://jakarta.ee/xml/ns/jakartaee";
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee 
https://jakarta.ee/xml/ns/jakartaee/beans_4_1.xsd";
+       version="4.1"
+       bean-discovery-mode="all"/>
diff --git 
a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java
 
b/modules/owb/src/test/webapp/instance/src/org/apache/webbeans/web/tomcat/testapp/InstanceProbe.java
similarity index 73%
copy from 
modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java
copy to 
modules/owb/src/test/webapp/instance/src/org/apache/webbeans/web/tomcat/testapp/InstanceProbe.java
index 526893d355..dac1fdd5e8 100644
--- 
a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java
+++ 
b/modules/owb/src/test/webapp/instance/src/org/apache/webbeans/web/tomcat/testapp/InstanceProbe.java
@@ -20,31 +20,36 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 
+import jakarta.annotation.PostConstruct;
 import jakarta.annotation.PreDestroy;
 import jakarta.inject.Inject;
-import jakarta.servlet.ServletContextEvent;
-import jakarta.servlet.ServletContextListener;
-import jakarta.servlet.annotation.WebListener;
 
-@WebListener
-public class LifecycleContextListener implements ServletContextListener {
+public class InstanceProbe {
 
     @Inject
-    private LifecycleGreeting greeting;
+    private ProbeGreeting greeting;
 
-    @Override
-    public void contextInitialized(ServletContextEvent event) {
-        event.getServletContext().setAttribute("owb.listener.greeting", 
greeting.message());
+    public boolean isInjected() {
+        return greeting != null;
+    }
+
+    @PostConstruct
+    void postConstruct() {
+        writeMarker("probePostConstruct.marker");
     }
 
     @PreDestroy
     void preDestroy() {
+        writeMarker("probePreDestroy.marker");
+    }
+
+    private static void writeMarker(String name) {
         String markerDirectory = System.getProperty("owb.test.marker.dir");
         if (markerDirectory != null) {
             try {
-                
Files.writeString(Path.of(markerDirectory).resolve("listenerPreDestroy.marker"),
 "marker");
+                Files.writeString(Path.of(markerDirectory).resolve(name), 
"marker");
             } catch (IOException e) {
-                throw new IllegalStateException("Unable to write listener 
lifecycle marker", e);
+                throw new IllegalStateException("Unable to write probe marker 
" + name, e);
             }
         }
     }
diff --git 
a/modules/owb/src/test/webapp/instance/src/org/apache/webbeans/web/tomcat/testapp/InstanceProbeServlet.java
 
b/modules/owb/src/test/webapp/instance/src/org/apache/webbeans/web/tomcat/testapp/InstanceProbeServlet.java
new file mode 100644
index 0000000000..b65d27aacd
--- /dev/null
+++ 
b/modules/owb/src/test/webapp/instance/src/org/apache/webbeans/web/tomcat/testapp/InstanceProbeServlet.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.webbeans.web.tomcat.testapp;
+
+import java.io.IOException;
+
+import jakarta.servlet.annotation.WebServlet;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import org.apache.tomcat.InstanceManager;
+
+@WebServlet("/instance-probe")
+public class InstanceProbeServlet extends HttpServlet {
+
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse 
response) throws IOException {
+        InstanceManager instanceManager = (InstanceManager) getServletContext()
+                .getAttribute(InstanceManager.class.getName());
+        ClassLoader original = Thread.currentThread().getContextClassLoader();
+        ClassLoader markerLoader = new ClassLoader(original) {
+        };
+        Thread.currentThread().setContextClassLoader(markerLoader);
+        try {
+            InstanceProbe byClass = (InstanceProbe) 
instanceManager.newInstance(InstanceProbe.class);
+            boolean classInjected = byClass.isInjected();
+            instanceManager.destroyInstance(byClass);
+            boolean classContext = 
Thread.currentThread().getContextClassLoader() == markerLoader;
+
+            InstanceProbe byName = (InstanceProbe) 
instanceManager.newInstance(InstanceProbe.class.getName());
+            boolean stringInjected = byName.isInjected();
+            instanceManager.destroyInstance(byName);
+            boolean stringContext = 
Thread.currentThread().getContextClassLoader() == markerLoader;
+
+            InstanceProbe byLoader = (InstanceProbe) 
instanceManager.newInstance(InstanceProbe.class.getName(),
+                    InstanceProbeServlet.class.getClassLoader());
+            boolean stringLoaderInjected = byLoader.isInjected();
+            instanceManager.destroyInstance(byLoader);
+            boolean stringLoaderContext = 
Thread.currentThread().getContextClassLoader() == markerLoader;
+
+            InstanceProbe byObject = new InstanceProbe();
+            instanceManager.newInstance(byObject);
+            boolean objectInjected = byObject.isInjected();
+            instanceManager.destroyInstance(byObject);
+            boolean objectContext = 
Thread.currentThread().getContextClassLoader() == markerLoader;
+
+            boolean contextRestored = classContext && stringContext && 
stringLoaderContext && objectContext;
+            response.setContentType("text/plain");
+            response.getWriter().println("class=" + injected(classInjected) + 
",string=" + injected(stringInjected)
+                    + ",stringLoader=" + injected(stringLoaderInjected) + 
",object=" + injected(objectInjected)
+                    + ",context=" + (contextRestored ? "restored" : 
"changed"));
+        } catch (Exception e) {
+            throw new IOException(e);
+        } finally {
+            Thread.currentThread().setContextClassLoader(original);
+        }
+    }
+
+    private static String injected(boolean injected) {
+        return injected ? "injected" : "not-injected";
+    }
+}
diff --git 
a/modules/owb/src/test/webapp/instance/src/org/apache/webbeans/web/tomcat/testapp/ProbeGreeting.java
 
b/modules/owb/src/test/webapp/instance/src/org/apache/webbeans/web/tomcat/testapp/ProbeGreeting.java
new file mode 100644
index 0000000000..db5dc328be
--- /dev/null
+++ 
b/modules/owb/src/test/webapp/instance/src/org/apache/webbeans/web/tomcat/testapp/ProbeGreeting.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.webbeans.web.tomcat.testapp;
+
+import jakarta.enterprise.context.ApplicationScoped;
+
+@ApplicationScoped
+public class ProbeGreeting {
+
+    public String message() {
+        return "probe-owb-4.1.1";
+    }
+}
diff --git a/modules/owb/src/test/webapp/jsp/index.jsp 
b/modules/owb/src/test/webapp/jsp/WEB-INF/tags/greeting.tag
similarity index 88%
copy from modules/owb/src/test/webapp/jsp/index.jsp
copy to modules/owb/src/test/webapp/jsp/WEB-INF/tags/greeting.tag
index 21e1a03c3b..8b168b8e3f 100644
--- a/modules/owb/src/test/webapp/jsp/index.jsp
+++ b/modules/owb/src/test/webapp/jsp/WEB-INF/tags/greeting.tag
@@ -14,7 +14,5 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 --%>
-<%@ page contentType="text/html; charset=UTF-8" %>
-<html>
-<body>${greeting.message}</body>
-</html>
+<%@ tag body-content="empty" %>
+tag:${greeting.message}
diff --git a/modules/owb/src/test/webapp/jsp/index.jsp 
b/modules/owb/src/test/webapp/jsp/included.jsp
similarity index 88%
copy from modules/owb/src/test/webapp/jsp/index.jsp
copy to modules/owb/src/test/webapp/jsp/included.jsp
index 21e1a03c3b..8a44919dab 100644
--- a/modules/owb/src/test/webapp/jsp/index.jsp
+++ b/modules/owb/src/test/webapp/jsp/included.jsp
@@ -14,7 +14,4 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 --%>
-<%@ page contentType="text/html; charset=UTF-8" %>
-<html>
-<body>${greeting.message}</body>
-</html>
+included:${greeting.message}
diff --git a/modules/owb/src/test/webapp/jsp/index.jsp 
b/modules/owb/src/test/webapp/jsp/index.jsp
index 21e1a03c3b..110f8cd896 100644
--- a/modules/owb/src/test/webapp/jsp/index.jsp
+++ b/modules/owb/src/test/webapp/jsp/index.jsp
@@ -15,6 +15,13 @@
   limitations under the License.
 --%>
 <%@ page contentType="text/html; charset=UTF-8" %>
+<%@ taglib prefix="owb" tagdir="/WEB-INF/tags" %>
 <html>
-<body>${greeting.message}</body>
+<body>
+<p>property:${greeting.message}</p>
+<p>method:${methodGreeting.message()}</p>
+<p>include:<jsp:include page="included.jsp"/></p>
+<p>tag:<owb:greeting/></p>
+<p>request:${requestGreeting.message}</p>
+</body>
 </html>
diff --git 
a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleServlet.java
 
b/modules/owb/src/test/webapp/jsp/src/org/apache/webbeans/web/tomcat/testapp/ElServlet.java
similarity index 52%
copy from 
modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleServlet.java
copy to 
modules/owb/src/test/webapp/jsp/src/org/apache/webbeans/web/tomcat/testapp/ElServlet.java
index 4d6d35be26..2623946371 100644
--- 
a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleServlet.java
+++ 
b/modules/owb/src/test/webapp/jsp/src/org/apache/webbeans/web/tomcat/testapp/ElServlet.java
@@ -17,51 +17,33 @@
 package org.apache.webbeans.web.tomcat.testapp;
 
 import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
 
-import jakarta.annotation.PostConstruct;
-import jakarta.annotation.PreDestroy;
-import jakarta.inject.Inject;
+import jakarta.el.ExpressionFactory;
+import jakarta.el.StandardELContext;
+import jakarta.el.ValueExpression;
+import jakarta.enterprise.inject.spi.BeanManager;
+import jakarta.enterprise.inject.spi.CDI;
 import jakarta.servlet.annotation.WebServlet;
 import jakarta.servlet.http.HttpServlet;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 
-@WebServlet("/lifecycle")
-public class LifecycleServlet extends HttpServlet {
+@WebServlet("/el")
+public class ElServlet extends HttpServlet {
 
     private static final long serialVersionUID = 1L;
 
-    @Inject
-    private LifecycleGreeting greeting;
-
-    @PostConstruct
-    void postConstruct() {
-        writeMarker("postConstruct.marker");
-    }
-
-    @PreDestroy
-    void preDestroy() {
-        writeMarker("preDestroy.marker");
-    }
-
     @Override
+    @SuppressWarnings("removal")
     protected void doGet(HttpServletRequest request, HttpServletResponse 
response) throws IOException {
-        String listener = (String) 
getServletContext().getAttribute("owb.listener.greeting");
-        String filter = (String) request.getAttribute("owb.filter.greeting");
+        BeanManager beanManager = CDI.current().getBeanManager();
+        ExpressionFactory expressionFactory = ExpressionFactory.newInstance();
+        StandardELContext context = new StandardELContext(expressionFactory);
+        context.addELResolver(beanManager.getELResolver());
+        ValueExpression expression = 
expressionFactory.createValueExpression(context, "#{greeting.message}",
+                String.class);
+        Object value = expression.getValue(context);
         response.setContentType("text/plain");
-        response.getWriter().println(greeting.message() + "|" + listener + "|" 
+ filter);
-    }
-
-    private static void writeMarker(String name) {
-        String markerDirectory = System.getProperty("owb.test.marker.dir");
-        if (markerDirectory != null) {
-            try {
-                Files.writeString(Path.of(markerDirectory).resolve(name), 
"marker");
-            } catch (IOException e) {
-                throw new IllegalStateException("Unable to write lifecycle 
marker " + name, e);
-            }
-        }
+        response.getWriter().println(value.toString());
     }
 }
diff --git 
a/modules/owb/src/test/webapp/jsp/src/org/apache/webbeans/web/tomcat/testapp/MethodGreeting.java
 
b/modules/owb/src/test/webapp/jsp/src/org/apache/webbeans/web/tomcat/testapp/MethodGreeting.java
new file mode 100644
index 0000000000..ddf5783783
--- /dev/null
+++ 
b/modules/owb/src/test/webapp/jsp/src/org/apache/webbeans/web/tomcat/testapp/MethodGreeting.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.webbeans.web.tomcat.testapp;
+
+import jakarta.enterprise.context.Dependent;
+import jakarta.inject.Named;
+
+@Named("methodGreeting")
+@Dependent
+public class MethodGreeting {
+
+    public String message() {
+        return "hello-owb-4.1.1";
+    }
+}
diff --git 
a/modules/owb/src/test/webapp/jsp/src/org/apache/webbeans/web/tomcat/testapp/RequestGreeting.java
 
b/modules/owb/src/test/webapp/jsp/src/org/apache/webbeans/web/tomcat/testapp/RequestGreeting.java
new file mode 100644
index 0000000000..89ea291431
--- /dev/null
+++ 
b/modules/owb/src/test/webapp/jsp/src/org/apache/webbeans/web/tomcat/testapp/RequestGreeting.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.webbeans.web.tomcat.testapp;
+
+import java.util.UUID;
+
+import jakarta.enterprise.context.RequestScoped;
+import jakarta.inject.Named;
+
+@Named("requestGreeting")
+@RequestScoped
+public class RequestGreeting {
+
+    private final String message = "request:" + UUID.randomUUID();
+
+    public String getMessage() {
+        return message;
+    }
+}
diff --git 
a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java
 
b/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java
index 526893d355..e8276bc4da 100644
--- 
a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java
+++ 
b/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java
@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 
+import jakarta.annotation.PostConstruct;
 import jakarta.annotation.PreDestroy;
 import jakarta.inject.Inject;
 import jakarta.servlet.ServletContextEvent;
@@ -37,14 +38,23 @@ public class LifecycleContextListener implements 
ServletContextListener {
         event.getServletContext().setAttribute("owb.listener.greeting", 
greeting.message());
     }
 
+    @PostConstruct
+    void postConstruct() {
+        writeMarker("listenerPostConstruct.marker");
+    }
+
     @PreDestroy
     void preDestroy() {
+        writeMarker("listenerPreDestroy.marker");
+    }
+
+    private static void writeMarker(String name) {
         String markerDirectory = System.getProperty("owb.test.marker.dir");
         if (markerDirectory != null) {
             try {
-                
Files.writeString(Path.of(markerDirectory).resolve("listenerPreDestroy.marker"),
 "marker");
+                Files.writeString(Path.of(markerDirectory).resolve(name), 
"marker");
             } catch (IOException e) {
-                throw new IllegalStateException("Unable to write listener 
lifecycle marker", e);
+                throw new IllegalStateException("Unable to write listener 
lifecycle marker " + name, e);
             }
         }
     }
diff --git 
a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleFilter.java
 
b/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleFilter.java
index 68a689eba8..2c37cb500e 100644
--- 
a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleFilter.java
+++ 
b/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleFilter.java
@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 
+import jakarta.annotation.PostConstruct;
 import jakarta.annotation.PreDestroy;
 import jakarta.inject.Inject;
 import jakarta.servlet.Filter;
@@ -46,6 +47,11 @@ public class LifecycleFilter implements Filter {
         chain.doFilter(request, response);
     }
 
+    @PostConstruct
+    void postConstruct() {
+        writeMarker("filterPostConstruct.marker");
+    }
+
     @PreDestroy
     void preDestroy() {
         writeMarker("filterPreDestroy.marker");
diff --git 
a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java
 
b/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleMarkerWriter.java
similarity index 66%
copy from 
modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java
copy to 
modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleMarkerWriter.java
index 526893d355..d72a49836c 100644
--- 
a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java
+++ 
b/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleMarkerWriter.java
@@ -20,31 +20,18 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 
-import jakarta.annotation.PreDestroy;
-import jakarta.inject.Inject;
-import jakarta.servlet.ServletContextEvent;
-import jakarta.servlet.ServletContextListener;
-import jakarta.servlet.annotation.WebListener;
+final class LifecycleMarkerWriter {
 
-@WebListener
-public class LifecycleContextListener implements ServletContextListener {
-
-    @Inject
-    private LifecycleGreeting greeting;
-
-    @Override
-    public void contextInitialized(ServletContextEvent event) {
-        event.getServletContext().setAttribute("owb.listener.greeting", 
greeting.message());
+    private LifecycleMarkerWriter() {
     }
 
-    @PreDestroy
-    void preDestroy() {
+    static void write(String name) {
         String markerDirectory = System.getProperty("owb.test.marker.dir");
         if (markerDirectory != null) {
             try {
-                
Files.writeString(Path.of(markerDirectory).resolve("listenerPreDestroy.marker"),
 "marker");
+                Files.writeString(Path.of(markerDirectory).resolve(name), 
"marker");
             } catch (IOException e) {
-                throw new IllegalStateException("Unable to write listener 
lifecycle marker", e);
+                throw new IllegalStateException("Unable to write lifecycle 
marker " + name, e);
             }
         }
     }
diff --git 
a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java
 
b/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleRequestListener.java
similarity index 58%
copy from 
modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java
copy to 
modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleRequestListener.java
index 526893d355..1f8d531542 100644
--- 
a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java
+++ 
b/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleRequestListener.java
@@ -16,36 +16,31 @@
  */
 package org.apache.webbeans.web.tomcat.testapp;
 
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
+import jakarta.annotation.PostConstruct;
 import jakarta.annotation.PreDestroy;
 import jakarta.inject.Inject;
-import jakarta.servlet.ServletContextEvent;
-import jakarta.servlet.ServletContextListener;
+import jakarta.servlet.ServletRequestEvent;
+import jakarta.servlet.ServletRequestListener;
 import jakarta.servlet.annotation.WebListener;
 
 @WebListener
-public class LifecycleContextListener implements ServletContextListener {
+public class LifecycleRequestListener implements ServletRequestListener {
 
     @Inject
     private LifecycleGreeting greeting;
 
-    @Override
-    public void contextInitialized(ServletContextEvent event) {
-        event.getServletContext().setAttribute("owb.listener.greeting", 
greeting.message());
+    @PostConstruct
+    void postConstruct() {
+        LifecycleMarkerWriter.write("requestListenerPostConstruct.marker");
     }
 
     @PreDestroy
     void preDestroy() {
-        String markerDirectory = System.getProperty("owb.test.marker.dir");
-        if (markerDirectory != null) {
-            try {
-                
Files.writeString(Path.of(markerDirectory).resolve("listenerPreDestroy.marker"),
 "marker");
-            } catch (IOException e) {
-                throw new IllegalStateException("Unable to write listener 
lifecycle marker", e);
-            }
-        }
+        LifecycleMarkerWriter.write("requestListenerPreDestroy.marker");
+    }
+
+    @Override
+    public void requestInitialized(ServletRequestEvent event) {
+        
event.getServletRequest().setAttribute("owb.request.listener.greeting", 
greeting.message());
     }
 }
diff --git 
a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleServlet.java
 
b/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleServlet.java
index 4d6d35be26..2e38046789 100644
--- 
a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleServlet.java
+++ 
b/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleServlet.java
@@ -48,10 +48,14 @@ public class LifecycleServlet extends HttpServlet {
 
     @Override
     protected void doGet(HttpServletRequest request, HttpServletResponse 
response) throws IOException {
+        request.getSession();
         String listener = (String) 
getServletContext().getAttribute("owb.listener.greeting");
         String filter = (String) request.getAttribute("owb.filter.greeting");
+        String requestListener = (String) 
request.getAttribute("owb.request.listener.greeting");
+        String sessionListener = (String) 
request.getSession().getAttribute("owb.session.listener.greeting");
         response.setContentType("text/plain");
-        response.getWriter().println(greeting.message() + "|" + listener + "|" 
+ filter);
+        response.getWriter().println(greeting.message() + "|" + listener + "|" 
+ filter + "|" + requestListener
+                + "|" + sessionListener);
     }
 
     private static void writeMarker(String name) {
diff --git 
a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java
 
b/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleSessionListener.java
similarity index 57%
copy from 
modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java
copy to 
modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleSessionListener.java
index 526893d355..8e270775bc 100644
--- 
a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java
+++ 
b/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleSessionListener.java
@@ -16,36 +16,31 @@
  */
 package org.apache.webbeans.web.tomcat.testapp;
 
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
+import jakarta.annotation.PostConstruct;
 import jakarta.annotation.PreDestroy;
 import jakarta.inject.Inject;
-import jakarta.servlet.ServletContextEvent;
-import jakarta.servlet.ServletContextListener;
 import jakarta.servlet.annotation.WebListener;
+import jakarta.servlet.http.HttpSessionEvent;
+import jakarta.servlet.http.HttpSessionListener;
 
 @WebListener
-public class LifecycleContextListener implements ServletContextListener {
+public class LifecycleSessionListener implements HttpSessionListener {
 
     @Inject
     private LifecycleGreeting greeting;
 
-    @Override
-    public void contextInitialized(ServletContextEvent event) {
-        event.getServletContext().setAttribute("owb.listener.greeting", 
greeting.message());
+    @PostConstruct
+    void postConstruct() {
+        LifecycleMarkerWriter.write("sessionListenerPostConstruct.marker");
     }
 
     @PreDestroy
     void preDestroy() {
-        String markerDirectory = System.getProperty("owb.test.marker.dir");
-        if (markerDirectory != null) {
-            try {
-                
Files.writeString(Path.of(markerDirectory).resolve("listenerPreDestroy.marker"),
 "marker");
-            } catch (IOException e) {
-                throw new IllegalStateException("Unable to write listener 
lifecycle marker", e);
-            }
-        }
+        LifecycleMarkerWriter.write("sessionListenerPreDestroy.marker");
+    }
+
+    @Override
+    public void sessionCreated(HttpSessionEvent event) {
+        event.getSession().setAttribute("owb.session.listener.greeting", 
greeting.message());
     }
 }
diff --git a/webapps/docs/cdi.xml b/webapps/docs/cdi.xml
index 2cf3fc4148..a7bdbca2f8 100644
--- a/webapps/docs/cdi.xml
+++ b/webapps/docs/cdi.xml
@@ -149,6 +149,11 @@ mvn clean verify]]></source>
     are supported when CDI support is enabled.
   </p>
 
+  <p>
+    EL method invocation against a normal-scoped CDI proxy bean is not
+    supported; use property access or a dependent bean instead.
+  </p>
+
   <p>
     Support for features that depend on optional CDI EL APIs or on CDI
     features not implemented by OpenWebBeans may vary. See


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to