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]
