From e9a1f99e272e546362e378562f049b01bce53035 Mon Sep 17 00:00:00 2001 From: Manfred Riem Date: Sun, 8 Dec 2024 11:49:52 -0600 Subject: [PATCH] Fixes #4325 - Add HandlesTypes extension --- .../piranha/core/api/HandlesTypesManager.java | 103 +++++++++ .../core/api/WebApplicationManager.java | 14 ++ .../core/impl/DefaultWebApplication.java | 56 +++-- .../impl/DefaultWebApplicationManager.java | 45 ++-- extension/coreprofile/pom.xml | 6 + .../coreprofile/CoreProfileExtension.java | 2 + .../src/main/java/module-info.java | 2 + extension/handlestypes/pom.xml | 74 +++++++ .../handlestypes/HandlesTypesExtension.java | 53 +++++ .../InternalHandlesTypesInitializer.java | 206 ++++++++++++++++++ .../internal/InternalHandlesTypesManager.java | 124 +++++++++++ .../src/main/java/module-info.java | 40 ++++ .../HandlesTypesExtensionTest.java | 52 +++++ .../InternalHandlesTypesInitializerTest.java | 96 ++++++++ .../InternalHandlesTypesManagerTest.java | 48 ++++ .../handlestypes/internal/TestA.java | 37 ++++ .../handlestypes/internal/TestB.java | 41 ++++ .../handlestypes/internal/TestC.java | 36 +++ .../handlestypes/internal/TestD.java | 36 +++ .../TestServletContainerInitializer.java | 47 ++++ extension/pom.xml | 1 + .../internal/InternalWebXmlProcessor.java | 4 - .../piranha/feature/webapp/WebAppFeature.java | 2 +- .../impl/AliasedDirectoryResource.java | 17 +- .../resource/impl/DefaultResourceManager.java | 2 +- test/coreprofile/arquillian/pom.xml | 7 + test/coreprofile/no_servlet_class/pom.xml | 142 ++++++++++++ .../no_servlet_class/EchoApplication.java | 42 ++++ .../no_servlet_class/EchoBean.java | 49 +++++ .../src/main/webapp/WEB-INF/web.xml | 12 + .../coreprofile/no_servlet_class/EchoIT.java | 24 ++ test/coreprofile/pom.xml | 1 + 32 files changed, 1382 insertions(+), 39 deletions(-) create mode 100644 core/api/src/main/java/cloud/piranha/core/api/HandlesTypesManager.java create mode 100644 extension/handlestypes/pom.xml create mode 100644 extension/handlestypes/src/main/java/cloud/piranha/extension/handlestypes/HandlesTypesExtension.java create mode 100644 extension/handlestypes/src/main/java/cloud/piranha/extension/handlestypes/internal/InternalHandlesTypesInitializer.java create mode 100644 extension/handlestypes/src/main/java/cloud/piranha/extension/handlestypes/internal/InternalHandlesTypesManager.java create mode 100644 extension/handlestypes/src/main/java/module-info.java create mode 100644 extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/HandlesTypesExtensionTest.java create mode 100644 extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/InternalHandlesTypesInitializerTest.java create mode 100644 extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/InternalHandlesTypesManagerTest.java create mode 100644 extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestA.java create mode 100644 extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestB.java create mode 100644 extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestC.java create mode 100644 extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestD.java create mode 100644 extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestServletContainerInitializer.java create mode 100644 test/coreprofile/no_servlet_class/pom.xml create mode 100644 test/coreprofile/no_servlet_class/src/main/java/cloud/piranha/test/coreprofile/no_servlet_class/EchoApplication.java create mode 100644 test/coreprofile/no_servlet_class/src/main/java/cloud/piranha/test/coreprofile/no_servlet_class/EchoBean.java create mode 100644 test/coreprofile/no_servlet_class/src/main/webapp/WEB-INF/web.xml create mode 100644 test/coreprofile/no_servlet_class/src/test/java/cloud/piranha/test/coreprofile/no_servlet_class/EchoIT.java diff --git a/core/api/src/main/java/cloud/piranha/core/api/HandlesTypesManager.java b/core/api/src/main/java/cloud/piranha/core/api/HandlesTypesManager.java new file mode 100644 index 0000000000..c9881c7df4 --- /dev/null +++ b/core/api/src/main/java/cloud/piranha/core/api/HandlesTypesManager.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package cloud.piranha.core.api; + +import java.util.Set; + +/** + * The manager that delivers support for the HandlesTypes annotation. + * + *

+ * Whenever the onStartup method of a ServletContainerInitializer is called it + * gets passed a set of classes that it expressed interest in. This manager + * delivers the way a web application can vend that set of classes. See the + * JavaDoc of the ServletContainerInitializer for more information about the + * onStartup method. + *

+ * + * @author Manfred Riem (mriem@manorrock.com) + */ +public interface HandlesTypesManager { + + /** + * Add the annotated class. + * + * @param annotationClass the annotation class. + * @param annotatedClass the annotated class. + */ + void addAnnotatedClass(Class annotationClass, Class annotatedClass); + + /** + * Add the extending class. + * + * @param baseClass the based class. + * @param extendingClass the extending class. + */ + void addExtendingClass(Class baseClass, Class extendingClass); + + /** + * Add the implementing class. + * + * @param interfaceClass the interface. + * @param implementingClass the implementing class. + */ + void addImplementingClass(Class interfaceClass, Class implementingClass); + + /** + * Get the annotated classes. + * + * @param annotationClass the annotation classes. + * @return the annotated classes. + */ + Set> getAnnotatedClasses(Class annotationClass); + + /** + * Get the extending classes. + * + * @param baseClass the base class. + * @return the set of extending classes. + */ + Set> getExtendingClasses(Class baseClass); + + /** + * Get the implementing classes. + * + * @param interfaceClass the interface class. + * @return the set of implementing classes. + */ + Set> getImplementingClasses(Class interfaceClass); + + /** + * Get the set of classes that either are annotated with the given classes, + * implement any of the given classes, or extend any of the given classes. + * + * @param classes the set of given classes. + * @return the set of classes or null if none found. + */ + Set> getClasses(Set> classes); +} diff --git a/core/api/src/main/java/cloud/piranha/core/api/WebApplicationManager.java b/core/api/src/main/java/cloud/piranha/core/api/WebApplicationManager.java index 2e7045c5da..72eb4895a2 100644 --- a/core/api/src/main/java/cloud/piranha/core/api/WebApplicationManager.java +++ b/core/api/src/main/java/cloud/piranha/core/api/WebApplicationManager.java @@ -69,6 +69,13 @@ public interface WebApplicationManager { */ DispatcherManager getDispatcherManager(); + /** + * Get the HandlesTypes manager. + * + * @return the HandlesTypes manager. + */ + HandlesTypesManager getHandlesTypesManager(); + /** * Get the HTTP session manager. * @@ -153,6 +160,13 @@ public interface WebApplicationManager { */ void setErrorPageManager(ErrorPageManager errorPageManager); + /** + * Set the HandlesTypes manager. + * + * @param handlesTypesManager the HandlesTypes manager. + */ + void setHandlesTypesManager(HandlesTypesManager handlesTypesManager); + /** * Set the HTTP session manager. * diff --git a/core/impl/src/main/java/cloud/piranha/core/impl/DefaultWebApplication.java b/core/impl/src/main/java/cloud/piranha/core/impl/DefaultWebApplication.java index 084051203e..4686b4ca49 100644 --- a/core/impl/src/main/java/cloud/piranha/core/impl/DefaultWebApplication.java +++ b/core/impl/src/main/java/cloud/piranha/core/impl/DefaultWebApplication.java @@ -93,6 +93,7 @@ import java.util.stream.Stream; import cloud.piranha.core.api.WebApplicationManager; import static java.lang.System.Logger.Level.INFO; +import java.util.Arrays; /** * The default WebApplication. @@ -505,14 +506,18 @@ public Dynamic addServlet(String servletName, String className) { DefaultServletEnvironment servletEnvironment = servletEnvironments.get(servletName); if (servletEnvironment == null) { servletEnvironment = new DefaultServletEnvironment(this, servletName); - servletEnvironment.setClassName(className); + if (className != null && !className.isBlank()) { + servletEnvironment.setClassName(className); + } servletEnvironments.put(servletName, servletEnvironment); } else { if (!isEmpty(servletEnvironment.getClassName())) { // Servlet already set, can't override return null; } - servletEnvironment.setClassName(className); + if (className != null && !className.isBlank()) { + servletEnvironment.setClassName(className); + } } return servletEnvironment; } @@ -984,7 +989,7 @@ public void initializeFilters() { try { environment.initialize(); environment.getFilter().init(environment); - } catch (Exception e) { + } catch (Throwable e) { LOGGER.log(WARNING, () -> "Unable to initialize filter: " + environment.getFilterName(), e); environment.setStatus(UNAVAILABLE); } @@ -1010,20 +1015,41 @@ public void initializeInitializers() { try { HandlesTypes annotation = initializer.getClass().getAnnotation(HandlesTypes.class); Set> classes = Collections.emptySet(); - if (annotation != null && manager.getAnnotationManager() != null) { + if (annotation != null) { Class[] value = annotation.value(); - // Get instances - Stream> instances = manager.getAnnotationManager() - .getInstances(value).stream(); - // Get classes by target type - List> annotations = manager.getAnnotationManager() - .getAnnotations(value); + if (manager.getAnnotationManager() != null) { + // Get instances + Stream> instances = manager.getAnnotationManager() + .getInstances(value).stream(); + + // Get classes by target type + List> annotations = manager.getAnnotationManager() + .getAnnotations(value); - Stream> classStream = annotations.stream().map(AnnotationInfo::getTargetType); + Stream> classStream = annotations.stream().map(AnnotationInfo::getTargetType); - classes = Stream.concat(instances, classStream).collect(Collectors.toSet()); - classes.addAll(manager.getAnnotationManager().getAnnotatedClasses(annotation.value())); + classes = Stream.concat(instances, classStream).collect(Collectors.toSet()); + classes.addAll(manager.getAnnotationManager().getAnnotatedClasses(annotation.value())); + } + + /* + * If we have a HandlesTypes manager we use it to get the + * set of classes we need to pass to the onStartup method. + */ + if (manager.getHandlesTypesManager() != null && value != null) { + Set> handlesTypesClasses + = manager.getHandlesTypesManager().getClasses( + Arrays.stream(value) + .collect(Collectors.toSet())); + if (handlesTypesClasses != null && !handlesTypesClasses.isEmpty()) { + if (classes == null) { + classes = handlesTypesClasses; + } else { + classes.addAll(handlesTypesClasses); + } + } + } } try { source = initializer; @@ -1031,7 +1057,7 @@ public void initializeInitializers() { } finally { source = null; } - } catch (Exception e) { + } catch (Throwable e) { LOGGER.log(WARNING, () -> "Initializer " + initializer.getClass().getName() + " failing onStartup", e); error = true; } @@ -1084,7 +1110,7 @@ private void initializeServlet(DefaultServletEnvironment environment) { } environment.getServlet().init(environment); LOGGER.log(DEBUG, "Initialized servlet: {0}", environment.servletName); - } catch (Exception e) { + } catch (Throwable e) { LOGGER.log(WARNING, () -> "Unable to initialize servlet: " + environment.className, e); environment.setStatus(ServletEnvironment.UNAVAILABLE); diff --git a/core/impl/src/main/java/cloud/piranha/core/impl/DefaultWebApplicationManager.java b/core/impl/src/main/java/cloud/piranha/core/impl/DefaultWebApplicationManager.java index a1184e352f..368fa2a7bf 100644 --- a/core/impl/src/main/java/cloud/piranha/core/impl/DefaultWebApplicationManager.java +++ b/core/impl/src/main/java/cloud/piranha/core/impl/DefaultWebApplicationManager.java @@ -31,6 +31,7 @@ import cloud.piranha.core.api.AsyncManager; import cloud.piranha.core.api.DispatcherManager; import cloud.piranha.core.api.ErrorPageManager; +import cloud.piranha.core.api.HandlesTypesManager; import cloud.piranha.core.api.HttpSessionManager; import cloud.piranha.core.api.JspManager; import cloud.piranha.core.api.LocaleEncodingManager; @@ -49,27 +50,32 @@ * @author Manfred Riem (mriem@manorrock.com) */ public class DefaultWebApplicationManager implements WebApplicationManager { - + /** * Stores the annotation manager. */ protected AnnotationManager annotationManager; - + /** * Stores the async manager. */ protected AsyncManager asyncManager = new DefaultAsyncManager(); - + /** * Stores the dispatcher manager. */ protected DispatcherManager dispatcherManager = new DefaultDispatcherManager(); - + /** * Stores the error page manager. */ protected ErrorPageManager errorPageManager = new DefaultErrorPageManager(); - + + /** + * Stores the HandlesTypes manager. + */ + protected HandlesTypesManager handlesTypesManager; + /** * Stores the HTTP session manager. */ @@ -79,22 +85,22 @@ public class DefaultWebApplicationManager implements WebApplicationManager { * Stores the JSP manager. */ protected JspManager jspManager = new DefaultJspManager(); - + /** * Stores the locale encoding manager. */ protected LocaleEncodingManager localeEncodingManager = new DefaultLocaleEncodingManager(); - + /** * Stores the multi-part manager. */ protected MultiPartManager multiPartManager = new DefaultMultiPartManager(); - + /** * Stores the object instance manager. */ protected ObjectInstanceManager objectInstanceManager = new DefaultObjectInstanceManager(); - + /** * Stores the resource manager. */ @@ -104,7 +110,7 @@ public class DefaultWebApplicationManager implements WebApplicationManager { * Stores the security manager. */ protected SecurityManager securityManager = new DefaultSecurityManager(); - + /** * Stores the servlet request manager. */ @@ -125,11 +131,6 @@ public AsyncManager getAsyncManager() { return asyncManager; } - /** - * Get the dispatcher manager. - * - * @return the dispatcher manager. - */ @Override public DispatcherManager getDispatcherManager() { return dispatcherManager; @@ -140,6 +141,11 @@ public ErrorPageManager getErrorPageManager() { return errorPageManager; } + @Override + public HandlesTypesManager getHandlesTypesManager() { + return handlesTypesManager; + } + @Override public HttpSessionManager getHttpSessionManager() { return httpSessionManager; @@ -201,8 +207,8 @@ public void setErrorPageManager(ErrorPageManager errorPageManager) { } @Override - public void setServletRequestManager(ServletRequestManager servletRequestManager) { - this.servletRequestManager = servletRequestManager; + public void setHandlesTypesManager(HandlesTypesManager handlesTypesManager) { + this.handlesTypesManager = handlesTypesManager; } @Override @@ -240,6 +246,11 @@ public void setSecurityManager(SecurityManager securityManager) { this.securityManager = securityManager; } + @Override + public void setServletRequestManager(ServletRequestManager servletRequestManager) { + this.servletRequestManager = servletRequestManager; + } + @Override public void setWelcomeFileManager(WelcomeFileManager welcomeFileManager) { this.welcomeFileManager = welcomeFileManager; diff --git a/extension/coreprofile/pom.xml b/extension/coreprofile/pom.xml index 9c6b42c82b..6cc854f67e 100644 --- a/extension/coreprofile/pom.xml +++ b/extension/coreprofile/pom.xml @@ -37,6 +37,12 @@ ${project.version} compile + + cloud.piranha.extension + piranha-extension-handlestypes + ${project.version} + compile + cloud.piranha.extension piranha-extension-herring diff --git a/extension/coreprofile/src/main/java/cloud/piranha/extension/coreprofile/CoreProfileExtension.java b/extension/coreprofile/src/main/java/cloud/piranha/extension/coreprofile/CoreProfileExtension.java index 53ab1598f5..2942966c5f 100644 --- a/extension/coreprofile/src/main/java/cloud/piranha/extension/coreprofile/CoreProfileExtension.java +++ b/extension/coreprofile/src/main/java/cloud/piranha/extension/coreprofile/CoreProfileExtension.java @@ -31,6 +31,7 @@ import cloud.piranha.core.api.WebApplicationExtensionContext; import cloud.piranha.extension.annotationscan.AnnotationScanExtension; import cloud.piranha.extension.annotationscan.classfile.ClassfileAnnotationScanExtension; +import cloud.piranha.extension.handlestypes.HandlesTypesExtension; import cloud.piranha.extension.herring.HerringExtension; import cloud.piranha.extension.scinitializer.ServletContainerInitializerExtension; import cloud.piranha.extension.webxml.WebXmlExtension; @@ -45,6 +46,7 @@ public class CoreProfileExtension implements WebApplicationExtension { @Override public void extend(WebApplicationExtensionContext context) { + context.add(HandlesTypesExtension.class); // HandlesTypes support context.add(HerringExtension.class); // Herring (JNDI) context.add(WebXmlExtension.class); context.add(getAnnotationScanExtensionClass()); diff --git a/extension/coreprofile/src/main/java/module-info.java b/extension/coreprofile/src/main/java/module-info.java index 76a2008e78..a7e2cff608 100644 --- a/extension/coreprofile/src/main/java/module-info.java +++ b/extension/coreprofile/src/main/java/module-info.java @@ -34,6 +34,7 @@ *

*
    *
  • Annotation Scanning
  • + *
  • HandlesTypes support
  • *
  • Herring (JNDI)
  • *
  • Jersey (REST)
  • *
  • Parsson (JSON)
  • @@ -50,6 +51,7 @@ requires transitive cloud.piranha.core.api; requires cloud.piranha.extension.annotationscan; requires cloud.piranha.extension.annotationscan.classfile; + requires cloud.piranha.extension.handlestypes; requires cloud.piranha.extension.herring; requires cloud.piranha.extension.jersey; requires cloud.piranha.extension.scinitializer; diff --git a/extension/handlestypes/pom.xml b/extension/handlestypes/pom.xml new file mode 100644 index 0000000000..e965f0293d --- /dev/null +++ b/extension/handlestypes/pom.xml @@ -0,0 +1,74 @@ + + + + 4.0.0 + + cloud.piranha.extension + project + 24.12.0-SNAPSHOT + + piranha-extension-handlestypes + jar + Piranha - Extension - Handles Types + + + + cloud.piranha.core + piranha-core-api + ${project.version} + provided + + + + cloud.piranha.core + piranha-core-impl + ${project.version} + test + + + org.junit.jupiter + junit-jupiter-api + test + 5.10.3 + + + org.junit.jupiter + junit-jupiter-params + test + 5.10.3 + + + org.junit.jupiter + junit-jupiter-engine + test + 5.10.3 + + + + + + maven-compiler-plugin + + + + testCompile + + test-compile + + + false + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + false + + + + + diff --git a/extension/handlestypes/src/main/java/cloud/piranha/extension/handlestypes/HandlesTypesExtension.java b/extension/handlestypes/src/main/java/cloud/piranha/extension/handlestypes/HandlesTypesExtension.java new file mode 100644 index 0000000000..14f4f25c8d --- /dev/null +++ b/extension/handlestypes/src/main/java/cloud/piranha/extension/handlestypes/HandlesTypesExtension.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package cloud.piranha.extension.handlestypes; + +import cloud.piranha.extension.handlestypes.internal.InternalHandlesTypesManager; +import cloud.piranha.extension.handlestypes.internal.InternalHandlesTypesInitializer; +import cloud.piranha.core.api.WebApplication; +import cloud.piranha.core.api.WebApplicationExtension; + +/** + * The HandlesTypes extension delivers a HandlesTypes manager. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +public class HandlesTypesExtension implements WebApplicationExtension { + + /** + * Configure the web application. + * + * @param webApplication the web application. + */ + @Override + public void configure(WebApplication webApplication) { + webApplication.getManager().setHandlesTypesManager( + new InternalHandlesTypesManager()); + webApplication.addInitializer(new InternalHandlesTypesInitializer()); + } +} diff --git a/extension/handlestypes/src/main/java/cloud/piranha/extension/handlestypes/internal/InternalHandlesTypesInitializer.java b/extension/handlestypes/src/main/java/cloud/piranha/extension/handlestypes/internal/InternalHandlesTypesInitializer.java new file mode 100644 index 0000000000..fe46cb2b12 --- /dev/null +++ b/extension/handlestypes/src/main/java/cloud/piranha/extension/handlestypes/internal/InternalHandlesTypesInitializer.java @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package cloud.piranha.extension.handlestypes.internal; + +import cloud.piranha.core.api.WebApplication; +import cloud.piranha.core.api.WebApplicationClassLoader; +import cloud.piranha.resource.api.ResourceManager; +import jakarta.servlet.ServletContainerInitializer; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.HandlesTypes; +import java.lang.System.Logger; +import static java.lang.System.Logger.Level.ERROR; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * The ServletContainerInitializer that delivers HandlesTypes processing. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +public class InternalHandlesTypesInitializer implements ServletContainerInitializer { + + /** + * Stores the logger. + */ + private static final Logger LOGGER + = System.getLogger(InternalHandlesTypesInitializer.class.getName()); + + @Override + public void onStartup(Set> classes, ServletContext context) + throws ServletException { + + WebApplication webApplication = (WebApplication) context; + if (webApplication != null) { + /* + * Determine the set of classes for all the ServletContainerInitializers. + */ + HashSet> collectedClasses = new HashSet<>(); + List initializers = webApplication.getInitializers(); + for (ServletContainerInitializer initializer : initializers) { + if (initializer.getClass().isAnnotationPresent(HandlesTypes.class)) { + HandlesTypes handlesTypes = initializer.getClass().getAnnotation(HandlesTypes.class); + if (handlesTypes.value() != null) { + collectedClasses.addAll( + Arrays.stream(handlesTypes.value()) + .collect(Collectors.toSet())); + } + } + } + + /* + * Walk the resource hierarchy and determine if the collected + * classes are used (as annotation, interface or extends) and if so + * add them to the HandlesTypes manager. + */ + WebApplicationClassLoader classLoader + = (WebApplicationClassLoader) webApplication.getClassLoader(); + if (classLoader != null) { + ResourceManager resourceManager = classLoader.getResourceManager(); + resourceManager.getAllLocations().parallel() + .forEach(location -> { + Class clazz = loadClass(webApplication, location); + if (clazz != null) { + processClass(webApplication, collectedClasses, clazz); + } + }); + } else { + LOGGER.log(ERROR, "Unable to process HandlesTypes because the classloader is incompatible"); + } + } + } + + /** + * Load a class from the given location. + * + * @param webApplication the web application. + * @param location the location of the class file. + * @return the loaded class, or null if it could not be loaded. + */ + private Class loadClass(WebApplication webApplication, String location) { + /* + * We do not look at module-info.java. + */ + if (location.toLowerCase().endsWith("module-info.class")) { + return null; + } + /* + * We do not look at any location that is not referring to a class. + */ + if (!location.toLowerCase().endsWith(".class")) { + return null; + } + String className = location.substring(1).replace('/', '.'); + className = className.substring(0, className.lastIndexOf('.')); + try { + return webApplication.getClassLoader().loadClass(className); + } catch (Throwable t) { + /* + * If we could not load it we cannot determine if we are a match. + */ + return null; + } + } + + /** + * Process the class to check if it matches any collected classes. + * + * @param webApplication the web application. + * @param collectedClasses the collected classes. + * @param clazz the class under consideration. + */ + private void processClass(WebApplication webApplication, HashSet> collectedClasses, Class clazz) { + for (Class collectedClass : collectedClasses) { + if (isClassAnnotatedWith(clazz, collectedClass)) { + webApplication.getManager().getHandlesTypesManager() + .addAnnotatedClass(collectedClass, clazz); + } + if (isClassExtending(clazz, collectedClass)) { + webApplication.getManager().getHandlesTypesManager() + .addExtendingClass(collectedClass, clazz); + } + if (isClassImplementing(clazz, collectedClass)) { + webApplication.getManager().getHandlesTypesManager() + .addImplementingClass(collectedClass, clazz); + } + } + } + + /** + * Check if the class is annotated with the given annotation. + * + * @param clazz the class under consideration. + * @param annotationClass the annotation class. + * @return true if it is, false otherwise. + */ + private boolean isClassAnnotatedWith(Class clazz, Class annotationClass) { + return annotationClass.isAnnotation() && clazz.getAnnotation(annotationClass) != null; + } + + /** + * Check if the class extends the given superclass. + * + * @param clazz the class. + * @param superClass the class being extended (aka the super class). + * @return true if it is, false otherwise. + */ + private boolean isClassExtending(Class clazz, Class superClass) { + Class currentClass = clazz.getSuperclass(); + while (currentClass != null) { + if (superClass.equals(currentClass)) { + return true; + } + currentClass = currentClass.getSuperclass(); + } + return false; + } + + /** + * Check if the class implements the given interface. + * + * @param clazz the class. + * @param interfaceClass the interface class. + * @return true if it is, false otherwise. + */ + private boolean isClassImplementing(Class clazz, Class interfaceClass) { + Class currentClass = clazz; + while (currentClass != null) { + for (Class iface : currentClass.getInterfaces()) { + if (interfaceClass.isAssignableFrom(iface)) { + return true; + } + } + currentClass = currentClass.getSuperclass(); + } + return false; + } +} diff --git a/extension/handlestypes/src/main/java/cloud/piranha/extension/handlestypes/internal/InternalHandlesTypesManager.java b/extension/handlestypes/src/main/java/cloud/piranha/extension/handlestypes/internal/InternalHandlesTypesManager.java new file mode 100644 index 0000000000..ce6d62954f --- /dev/null +++ b/extension/handlestypes/src/main/java/cloud/piranha/extension/handlestypes/internal/InternalHandlesTypesManager.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package cloud.piranha.extension.handlestypes.internal; + +import cloud.piranha.core.api.HandlesTypesManager; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * The HandlesTypes manager. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +public class InternalHandlesTypesManager implements HandlesTypesManager { + + /** + * Stores the annotated classes. + */ + private final ConcurrentHashMap, Set>> annotatedClasses = new ConcurrentHashMap<>(); + + /** + * Stores the extending classes. + */ + private final ConcurrentHashMap, Set>> extendingClasses = new ConcurrentHashMap<>(); + + /** + * Stores the implementing classes. + */ + private final ConcurrentHashMap, Set>> implementingClasses = new ConcurrentHashMap<>(); + + /** + * Constructor. + */ + public InternalHandlesTypesManager() { + } + + @Override + public void addAnnotatedClass(Class annotationClass, Class annotatedClass) { + if (!annotatedClasses.containsKey(annotationClass)) { + HashSet> hashSet = new HashSet<>(); + hashSet.add(annotatedClass); + annotatedClasses.put(annotationClass, hashSet); + } else { + annotatedClasses.get(annotationClass).add(annotatedClass); + } + } + + @Override + public void addExtendingClass(Class baseClass, Class extendingClass) { + if (!extendingClasses.containsKey(baseClass)) { + HashSet> hashSet = new HashSet<>(); + hashSet.add(extendingClass); + extendingClasses.put(baseClass, hashSet); + } else { + extendingClasses.get(baseClass).add(extendingClass); + } + } + + @Override + public void addImplementingClass(Class interfaceClass, Class implementingClass) { + if (!implementingClasses.containsKey(interfaceClass)) { + HashSet> hashSet = new HashSet<>(); + hashSet.add(implementingClass); + implementingClasses.put(interfaceClass, hashSet); + } else { + implementingClasses.get(interfaceClass).add(implementingClass); + } + } + + @Override + public Set> getAnnotatedClasses(Class annotationClass) { + return annotatedClasses.getOrDefault(annotationClass, new HashSet<>()); + } + + @Override + public Set> getExtendingClasses(Class baseClass) { + return extendingClasses.getOrDefault(baseClass, new HashSet<>()); + } + + @Override + public Set> getImplementingClasses(Class interfaceClass) { + return implementingClasses.getOrDefault(interfaceClass, new HashSet<>()); + } + + @Override + public Set> getClasses(Set> classes) { + HashSet> result = new HashSet<>(); + if (classes != null) { + for (Class clazz : classes) { + result.addAll(getAnnotatedClasses(clazz)); + result.addAll(getExtendingClasses(clazz)); + result.addAll(getImplementingClasses(clazz)); + } + } + return result.isEmpty() ? null : result; + } +} diff --git a/extension/handlestypes/src/main/java/module-info.java b/extension/handlestypes/src/main/java/module-info.java new file mode 100644 index 0000000000..e8f3be2498 --- /dev/null +++ b/extension/handlestypes/src/main/java/module-info.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * The module that delivers HandlesTypes annotation support. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +module cloud.piranha.extension.handlestypes { + + exports cloud.piranha.extension.handlestypes; + opens cloud.piranha.extension.handlestypes; + requires transitive cloud.piranha.core.api; + requires java.logging; +} diff --git a/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/HandlesTypesExtensionTest.java b/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/HandlesTypesExtensionTest.java new file mode 100644 index 0000000000..d671f76107 --- /dev/null +++ b/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/HandlesTypesExtensionTest.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package cloud.piranha.extension.handlestypes; + +import cloud.piranha.core.api.WebApplication; +import cloud.piranha.core.impl.DefaultWebApplication; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * The JUnit tests for the HandlesTypesExtension class. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +public class HandlesTypesExtensionTest { + + /** + * Test configure method. + */ + @Test + public void testConfigure() { + WebApplication webApplication = new DefaultWebApplication(); + HandlesTypesExtension extension = new HandlesTypesExtension(); + extension.configure(webApplication); + assertNotNull(webApplication.getManager().getHandlesTypesManager()); + } +} diff --git a/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/InternalHandlesTypesInitializerTest.java b/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/InternalHandlesTypesInitializerTest.java new file mode 100644 index 0000000000..c847dfcea5 --- /dev/null +++ b/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/InternalHandlesTypesInitializerTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package cloud.piranha.extension.handlestypes.internal; + +import cloud.piranha.core.api.HandlesTypesManager; +import cloud.piranha.core.impl.DefaultWebApplication; +import cloud.piranha.core.impl.DefaultWebApplicationClassLoader; +import cloud.piranha.extension.handlestypes.HandlesTypesExtension; +import cloud.piranha.resource.impl.AliasedDirectoryResource; +import cloud.piranha.resource.impl.DefaultResourceManager; +import java.io.File; +import java.util.HashSet; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * The JUnit tests for the InternalHandlesTypesInitializer class. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +public class InternalHandlesTypesInitializerTest { + + /** + * Test onStartup method. + */ + @Test + public void testOnStartup() throws Exception { + DefaultWebApplicationClassLoader classLoader = new DefaultWebApplicationClassLoader(); + DefaultResourceManager resourceManager = new DefaultResourceManager(); + resourceManager.addResource(new AliasedDirectoryResource( + new File("target/test-classes"), "/WEB-INF/classes")); + classLoader.setResourceManager(resourceManager); + DefaultWebApplication webApplication = new DefaultWebApplication(); + webApplication.setClassLoader(classLoader); + HandlesTypesExtension extension = new HandlesTypesExtension(); + extension.configure(webApplication); + webApplication.addInitializer(new TestServletContainerInitializer()); + + webApplication.initialize(); + + /* + * Verify a HandlesTypesManager was installed. + */ + HandlesTypesManager manager = webApplication.getManager().getHandlesTypesManager(); + assertNotNull(manager); + + /* + * Verify that for annotation TestB we have A listed as a class of interest. + */ + assertFalse(manager.getAnnotatedClasses(TestB.class).isEmpty()); + + /* + * Verify that for super class TestC we have A listed as a class of interest. + */ + assertFalse(manager.getExtendingClasses(TestC.class).isEmpty()); + + /* + * Verify that for interface TestD we have A listed as a class of interest. + */ + assertFalse(manager.getImplementingClasses(TestD.class).isEmpty()); + + /* + * Verify that we can get a combined set and it should be not empty. + */ + HashSet> classes = new HashSet<>(); + classes.add(TestB.class); + classes.add(TestC.class); + classes.add(TestD.class); + assertFalse(manager.getClasses(classes).isEmpty()); + } +} diff --git a/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/InternalHandlesTypesManagerTest.java b/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/InternalHandlesTypesManagerTest.java new file mode 100644 index 0000000000..5057f01990 --- /dev/null +++ b/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/InternalHandlesTypesManagerTest.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package cloud.piranha.extension.handlestypes.internal; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * The JUnit tests for the InternalHandlesTypesManager class. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +public class InternalHandlesTypesManagerTest { + + /** + * Test getClasses method. + */ + @Test + public void testGetClasses() { + InternalHandlesTypesManager manager = new InternalHandlesTypesManager(); + assertNull(manager.getClasses(null)); + } +} diff --git a/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestA.java b/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestA.java new file mode 100644 index 0000000000..d23d6ef9a4 --- /dev/null +++ b/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestA.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR TestA PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package cloud.piranha.extension.handlestypes.internal; + +/** + * Test class. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +@TestB +public class TestA extends TestC implements TestD { +} diff --git a/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestB.java b/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestB.java new file mode 100644 index 0000000000..003e472624 --- /dev/null +++ b/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestB.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package cloud.piranha.extension.handlestypes.internal; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Test annotation. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface TestB { + +} diff --git a/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestC.java b/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestC.java new file mode 100644 index 0000000000..a639b7bc40 --- /dev/null +++ b/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestC.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR TestA PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package cloud.piranha.extension.handlestypes.internal; + +/** + * Test class. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +public class TestC { +} diff --git a/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestD.java b/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestD.java new file mode 100644 index 0000000000..f818184274 --- /dev/null +++ b/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestD.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR TestA PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package cloud.piranha.extension.handlestypes.internal; + +/** + * A test interface. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +public interface TestD { +} diff --git a/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestServletContainerInitializer.java b/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestServletContainerInitializer.java new file mode 100644 index 0000000000..4f4fd8e8c8 --- /dev/null +++ b/extension/handlestypes/src/test/java/cloud/piranha/extension/handlestypes/internal/TestServletContainerInitializer.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package cloud.piranha.extension.handlestypes.internal; + +import jakarta.servlet.ServletContainerInitializer; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.HandlesTypes; +import java.util.Set; + +/** + * A test ServletContainerInitializer. + * + * @author Manfred Riem (mriem@manorrock.com) + */ +@HandlesTypes(value = { TestB.class, TestC.class, TestD.class }) +public class TestServletContainerInitializer implements ServletContainerInitializer { + + @Override + public void onStartup(Set> c, ServletContext ctx) throws ServletException { + } +} diff --git a/extension/pom.xml b/extension/pom.xml index c513828f18..45a9bac255 100644 --- a/extension/pom.xml +++ b/extension/pom.xml @@ -30,6 +30,7 @@ exousia expressly fileupload + handlestypes hazelcast herring hibernate-validator diff --git a/extension/webxml/src/main/java/cloud/piranha/extension/webxml/internal/InternalWebXmlProcessor.java b/extension/webxml/src/main/java/cloud/piranha/extension/webxml/internal/InternalWebXmlProcessor.java index cb377b18a2..760aaa11e7 100644 --- a/extension/webxml/src/main/java/cloud/piranha/extension/webxml/internal/InternalWebXmlProcessor.java +++ b/extension/webxml/src/main/java/cloud/piranha/extension/webxml/internal/InternalWebXmlProcessor.java @@ -514,10 +514,6 @@ private void processServlets(WebApplication webApplication, WebXml webXml) { if (!isEmpty(jspFile)) { dynamic = webApplication.addJspFile(servlet.getServletName(), jspFile); } else { - if (isEmpty(servlet.getClassName())) { - servlet.setClassName(servlet.getServletName()); - LOGGER.log(DEBUG, "Setting servlet-class from servlet-name"); - } dynamic = webApplication.addServlet(servlet.getServletName(), servlet.getClassName()); } diff --git a/feature/webapp/src/main/java/cloud/piranha/feature/webapp/WebAppFeature.java b/feature/webapp/src/main/java/cloud/piranha/feature/webapp/WebAppFeature.java index 929d1090c3..71cffd02b5 100644 --- a/feature/webapp/src/main/java/cloud/piranha/feature/webapp/WebAppFeature.java +++ b/feature/webapp/src/main/java/cloud/piranha/feature/webapp/WebAppFeature.java @@ -200,7 +200,7 @@ public void init() { try { webApplication.initialize(); - } catch (Exception e) { + } catch (Throwable e) { LOGGER.log(ERROR, "Failed to initialize web application"); } } diff --git a/resource/impl/src/main/java/cloud/piranha/resource/impl/AliasedDirectoryResource.java b/resource/impl/src/main/java/cloud/piranha/resource/impl/AliasedDirectoryResource.java index 7a6ea7aad5..752b150b3e 100644 --- a/resource/impl/src/main/java/cloud/piranha/resource/impl/AliasedDirectoryResource.java +++ b/resource/impl/src/main/java/cloud/piranha/resource/impl/AliasedDirectoryResource.java @@ -31,10 +31,15 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; import static java.lang.System.Logger.Level.WARNING; import java.net.MalformedURLException; import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.function.Predicate; import java.util.stream.Stream; /** @@ -112,7 +117,17 @@ public InputStream getResourceAsStream(String location) { @Override public Stream getAllLocations() { - return Stream.empty(); + try { + Path rootPath = Paths.get(rootDirectory.toURI()); + Path root = Paths.get("/"); + return Files.walk(rootPath) + .filter(Predicate.not(Files::isDirectory)) + .map(rootPath::relativize) + .map(root::resolve) + .map(p -> p.toString().replace("\\", "/")); + } catch (IOException e) { + return Stream.empty(); + } } /** diff --git a/resource/impl/src/main/java/cloud/piranha/resource/impl/DefaultResourceManager.java b/resource/impl/src/main/java/cloud/piranha/resource/impl/DefaultResourceManager.java index bd985e3990..62c2667ede 100644 --- a/resource/impl/src/main/java/cloud/piranha/resource/impl/DefaultResourceManager.java +++ b/resource/impl/src/main/java/cloud/piranha/resource/impl/DefaultResourceManager.java @@ -143,7 +143,7 @@ public InputStream getResourceAsStream(String location) { @Override public Stream getAllLocations() { - return resources.stream().flatMap(Resource::getAllLocations); + return resources.parallelStream().flatMap(Resource::getAllLocations); } @Override diff --git a/test/coreprofile/arquillian/pom.xml b/test/coreprofile/arquillian/pom.xml index 7e600f6f66..df7c523984 100644 --- a/test/coreprofile/arquillian/pom.xml +++ b/test/coreprofile/arquillian/pom.xml @@ -76,6 +76,13 @@ + org.apache.maven.plugins diff --git a/test/coreprofile/no_servlet_class/pom.xml b/test/coreprofile/no_servlet_class/pom.xml new file mode 100644 index 0000000000..304ddea919 --- /dev/null +++ b/test/coreprofile/no_servlet_class/pom.xml @@ -0,0 +1,142 @@ + + + + 4.0.0 + + cloud.piranha.test.coreprofile + project + 24.12.0-SNAPSHOT + + piranha-test-coreprofile-no_servlet_class + war + Piranha - Test - Core Profile - No servlet-class specified + + + ${project.version} + UTF-8 + + + + jakarta.platform + jakarta.jakartaee-core-api + provided + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.jupiter + junit-jupiter-params + test + + + + piranha-test-coreprofile-no_servlet_class + + + cloud.piranha.maven + piranha-maven-plugin + ${piranha.version} + + + pre-integration-test + pre-integration-test + + start + + + + post-integration-test + post-integration-test + + stop + + + + + ${httpPort} + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${java.version} + + + + org.apache.maven.plugins + maven-failsafe-plugin + ${maven-failsafe-plugin.version} + + + + integration-test + verify + + + + + 1 + + ${httpPort} + + + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + false + + + + org.codehaus.mojo + build-helper-maven-plugin + + + reserve-network-port + + reserve-network-port + + package + + + httpPort + + + + + + + + + + debug + + + + cloud.piranha.maven + piranha-maven-plugin + ${project.version} + + -Xdebug -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=9009 + + + + + + + diff --git a/test/coreprofile/no_servlet_class/src/main/java/cloud/piranha/test/coreprofile/no_servlet_class/EchoApplication.java b/test/coreprofile/no_servlet_class/src/main/java/cloud/piranha/test/coreprofile/no_servlet_class/EchoApplication.java new file mode 100644 index 0000000000..6bc1632b46 --- /dev/null +++ b/test/coreprofile/no_servlet_class/src/main/java/cloud/piranha/test/coreprofile/no_servlet_class/EchoApplication.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package cloud.piranha.test.coreprofile.no_servlet_class; + +import jakarta.ws.rs.core.Application; +import java.util.HashSet; +import java.util.Set; + +public class EchoApplication extends Application { + + @Override + public Set> getClasses() { + Set> classes = new HashSet<>(); + classes.add(EchoBean.class); + return classes; + } +} diff --git a/test/coreprofile/no_servlet_class/src/main/java/cloud/piranha/test/coreprofile/no_servlet_class/EchoBean.java b/test/coreprofile/no_servlet_class/src/main/java/cloud/piranha/test/coreprofile/no_servlet_class/EchoBean.java new file mode 100644 index 0000000000..45e749eff2 --- /dev/null +++ b/test/coreprofile/no_servlet_class/src/main/java/cloud/piranha/test/coreprofile/no_servlet_class/EchoBean.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package cloud.piranha.test.coreprofile.no_servlet_class; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN; + +@Path("") +public class EchoBean { + + /** + * Get the 'echo' string. + * + * @return 'echo' + */ + @GET + @Produces(TEXT_PLAIN) + @Path("/echo") + public String echo() { + return "echo"; + } +} diff --git a/test/coreprofile/no_servlet_class/src/main/webapp/WEB-INF/web.xml b/test/coreprofile/no_servlet_class/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..953bb4c7f4 --- /dev/null +++ b/test/coreprofile/no_servlet_class/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,12 @@ + + + cloud.piranha.test.coreprofile.no_servlet_class.EchoApplication + + + cloud.piranha.test.coreprofile.no_servlet_class.EchoApplication + /* + + + 30 + + diff --git a/test/coreprofile/no_servlet_class/src/test/java/cloud/piranha/test/coreprofile/no_servlet_class/EchoIT.java b/test/coreprofile/no_servlet_class/src/test/java/cloud/piranha/test/coreprofile/no_servlet_class/EchoIT.java new file mode 100644 index 0000000000..81c990f52d --- /dev/null +++ b/test/coreprofile/no_servlet_class/src/test/java/cloud/piranha/test/coreprofile/no_servlet_class/EchoIT.java @@ -0,0 +1,24 @@ +package cloud.piranha.test.coreprofile.no_servlet_class; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; + +class EchoIT { + + private String httpPort = System.getProperty("httpPort"); + + @Test + void testEcho() throws Exception { + HttpClient client = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest + .newBuilder(new URI("http://localhost:" + httpPort + "/piranha-test-coreprofile-no_servlet_class/echo")) + .build(); + HttpResponse response = client.send(request, BodyHandlers.ofString()); + assertEquals("echo", response.body()); + } +} diff --git a/test/coreprofile/pom.xml b/test/coreprofile/pom.xml index 595e90847a..3b14af65a7 100644 --- a/test/coreprofile/pom.xml +++ b/test/coreprofile/pom.xml @@ -33,5 +33,6 @@ arquillian integration json + no_servlet_class