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

robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-core.git

commit 69e7eb53495c377f384c924f9a234db2ae4d4b70
Author: Robert Lazarski <[email protected]>
AuthorDate: Sun Apr 5 16:19:07 2026 -1000

    Wire axis2-openapi module into springbootdemo WildFly sample
    
    - Register OpenApiServlet directly in Axis2WebAppInitializer at
      /openapi.json, /openapi.yaml, /swagger-ui — bypasses Spring MVC
      DispatcherServlet which is not wired in this WAR deployment
    - Add openapi-2.0.1-SNAPSHOT.mar to WEB-INF/modules via antrun so
      AxisServlet can engage the openapi module from axis2.xml
    - Bypass JWT auth and POST-only filter for OpenAPI GET requests in
      JWTAuthenticationFilter.requiresAuthentication() and
      HTTPPostOnlyRejectionFilter.doFilterInternal()
    - Add @Order(2) OpenAPI security filter chain in Axis2Application
      to pass OpenAPI paths through without authentication
    - Apply all security filter fixes to springbootdemo-tomcat11 as well
    
    Tested on WildFly 39 + OpenJDK 25: all three endpoints return 200,
    /openapi.json serves full OpenAPI 3.0.1 JSON, /swagger-ui returns
    Swagger UI HTML. Existing /services/* JWT-protected endpoints
    continue to require authentication.
    
    Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
---
 .../userguide/springboot/Axis2Application.java     |  2 +-
 .../webservices/HTTPPostOnlyRejectionFilter.java   |  7 ++
 .../webservices/JWTAuthenticationFilter.java       |  4 ++
 .../userguide/src/userguide/springbootdemo/pom.xml |  8 +++
 .../userguide/springboot/Axis2Application.java     |  2 +-
 .../configuration/Axis2WebAppInitializer.java      | 59 +++++++++-------
 .../springboot/configuration/OpenApiServlet.java   | 81 ++++++++++++++++++++++
 .../webservices/HTTPPostOnlyRejectionFilter.java   |  7 ++
 .../webservices/JWTAuthenticationFilter.java       |  4 ++
 9 files changed, 147 insertions(+), 27 deletions(-)

diff --git 
a/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/Axis2Application.java
 
b/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/Axis2Application.java
index 838d1bf3b6..bb4b5fe487 100644
--- 
a/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/Axis2Application.java
+++ 
b/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/Axis2Application.java
@@ -355,7 +355,7 @@ public class Axis2Application extends 
SpringBootServletInitializer {
             public boolean matches(HttpServletRequest request) {
                 String uri = request.getRequestURI();
                 for (String path : OPENAPI_PATHS) {
-                    if (uri.equals(path) || uri.startsWith(path + "/")) {
+                    if (uri.endsWith(path) || uri.contains(path + "/")) {
                         return true;
                     }
                 }
diff --git 
a/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java
 
b/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java
index ba74dbc1e4..f2524f6d4a 100644
--- 
a/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java
+++ 
b/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java
@@ -55,6 +55,13 @@ public class HTTPPostOnlyRejectionFilter extends 
OncePerRequestFilter {
         
         logger.trace(logPrefix + "starting ... ");
         
+        String uri = request.getRequestURI();
+        boolean isOpenApiPath = uri.endsWith("/openapi.json") || 
uri.endsWith("/openapi.yaml") || uri.endsWith("/swagger-ui");
+        if (isOpenApiPath) {
+            filterChain.doFilter(request, response);
+            return;
+        }
+
         if (!request.getMethod().equals("POST")) {
 
            String ip = "unknown";
diff --git 
a/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java
 
b/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java
index 4b6e818a9a..59448a68a8 100644
--- 
a/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java
+++ 
b/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java
@@ -55,6 +55,10 @@ public class JWTAuthenticationFilter extends 
AbstractAuthenticationProcessingFil
 
     @Override
     protected boolean requiresAuthentication(HttpServletRequest request, 
HttpServletResponse response) {
+        String uri = request.getRequestURI();
+        if (uri.endsWith("/openapi.json") || uri.endsWith("/openapi.yaml") || 
uri.endsWith("/swagger-ui")) {
+            return false; // OpenAPI documentation endpoints are public
+        }
         return true;
     }
 
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/pom.xml 
b/modules/samples/userguide/src/userguide/springbootdemo/pom.xml
index c1de1b099e..4184fa663d 100644
--- a/modules/samples/userguide/src/userguide/springbootdemo/pom.xml
+++ b/modules/samples/userguide/src/userguide/springbootdemo/pom.xml
@@ -370,6 +370,10 @@
                                         <include name="axis2.xml"/>
                                     </fileset>
                                 </copy>
+                                <!-- Create openapi module archive for 
WEB-INF/modules -->
+                                <mkdir 
dir="${project.build.directory}/deploy/axis2-json-api.war/WEB-INF/modules"/>
+                                <copy 
file="${settings.localRepository}/org/apache/axis2/axis2-openapi/2.0.1-SNAPSHOT/axis2-openapi-2.0.1-SNAPSHOT.jar"
+                                      
tofile="${project.build.directory}/deploy/axis2-json-api.war/WEB-INF/modules/openapi-2.0.1-SNAPSHOT.mar"/>
                                 <unzip 
src="${project.build.directory}/axis2-json-api-0.0.1-SNAPSHOT.war" 
dest="${project.build.directory}/exploded"/>
                                 <jar 
jarfile="${project.build.directory}/exploded/WEB-INF/services/Login.aar">
                                     <metainf 
file="resources-axis2/login_resources/services.xml"/>
@@ -385,6 +389,10 @@
                                         <include name="axis2.xml"/>
                                     </fileset>
                                 </copy>
+                                <!-- Create openapi module archive for 
exploded WEB-INF/modules -->
+                                <mkdir 
dir="${project.build.directory}/exploded/WEB-INF/modules"/>
+                                <copy 
file="${settings.localRepository}/org/apache/axis2/axis2-openapi/2.0.1-SNAPSHOT/axis2-openapi-2.0.1-SNAPSHOT.jar"
+                                      
tofile="${project.build.directory}/exploded/WEB-INF/modules/openapi-2.0.1-SNAPSHOT.mar"/>
                             </target>
                         </configuration>
                         <goals>
diff --git 
a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/Axis2Application.java
 
b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/Axis2Application.java
index c6e442891c..2bb756381a 100644
--- 
a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/Axis2Application.java
+++ 
b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/Axis2Application.java
@@ -349,7 +349,7 @@ public class Axis2Application extends 
SpringBootServletInitializer {
             public boolean matches(HttpServletRequest request) {
                 String uri = request.getRequestURI();
                 for (String path : OPENAPI_PATHS) {
-                    if (uri.equals(path) || uri.startsWith(path + "/")) {
+                    if (uri.endsWith(path) || uri.contains(path + "/")) {
                         return true;
                     }
                 }
diff --git 
a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/Axis2WebAppInitializer.java
 
b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/Axis2WebAppInitializer.java
index 38e998b5d5..03dfa46bd3 100644
--- 
a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/Axis2WebAppInitializer.java
+++ 
b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/Axis2WebAppInitializer.java
@@ -18,13 +18,13 @@
  * under the License.
  */
 package userguide.springboot.configuration;
- 
+
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.axis2.transport.http.AxisServlet;
 import org.springframework.boot.web.servlet.ServletContextInitializer;
-import org.springframework.context.annotation.Configuration; 
-import 
org.springframework.web.context.support.AnnotationConfigWebApplicationContext;  
 
+import org.springframework.context.annotation.Configuration;
+import 
org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
 import org.springframework.core.annotation.Order;
 
 import org.springframework.beans.factory.annotation.Autowired;
@@ -33,40 +33,49 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.PropertySource;
 import 
org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
 
-import jakarta.servlet.ServletContext; 
-import jakarta.servlet.ServletRegistration; 
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletRegistration;
+
+import java.util.Set;
 
-import java.util.Set; 
- 
 @Configuration
 @Order(4)
-public class Axis2WebAppInitializer implements ServletContextInitializer { 
- 
-    private static final Logger logger = 
LogManager.getLogger(Axis2WebAppInitializer.class); 
-    private static final String SERVICES_MAPPING = "/services/*"; 
- 
-    @Override 
-    public void onStartup(ServletContext container) { 
+public class Axis2WebAppInitializer implements ServletContextInitializer {
+
+    private static final Logger logger = 
LogManager.getLogger(Axis2WebAppInitializer.class);
+    private static final String SERVICES_MAPPING = "/services/*";
+
+    @Override
+    public void onStartup(ServletContext container) {
         logger.warn("inside onStartup() ...");
-        // Create the 'root' Spring application context 
-        AnnotationConfigWebApplicationContext ctx = new 
AnnotationConfigWebApplicationContext(); 
- 
-        addAxis2Servlet(container, ctx); 
+        // Create the 'root' Spring application context
+        AnnotationConfigWebApplicationContext ctx = new 
AnnotationConfigWebApplicationContext();
+
+        addAxis2Servlet(container, ctx);
+        addOpenApiServlet(container);
         logger.warn("onStartup() completed ...");
     }
- 
-    private void addAxis2Servlet(ServletContext container, 
AnnotationConfigWebApplicationContext ctx) { 
+
+    private void addAxis2Servlet(ServletContext container, 
AnnotationConfigWebApplicationContext ctx) {
 
         ServletRegistration.Dynamic dispatcher = container.addServlet(
           "AxisServlet", new AxisServlet());
         dispatcher.setLoadOnStartup(1);
         Set<String> mappingConflicts = dispatcher.addMapping(SERVICES_MAPPING);
-        if (!mappingConflicts.isEmpty()) { 
-            for (String s : mappingConflicts) { 
-                logger.error("Mapping conflict: " + s); 
-            } 
-            throw new IllegalStateException("'AxisServlet' could not be mapped 
to '" + SERVICES_MAPPING + "'"); 
+        if (!mappingConflicts.isEmpty()) {
+            for (String s : mappingConflicts) {
+                logger.error("Mapping conflict: " + s);
+            }
+            throw new IllegalStateException("'AxisServlet' could not be mapped 
to '" + SERVICES_MAPPING + "'");
         }
     }
 
+    private void addOpenApiServlet(ServletContext container) {
+        ServletRegistration.Dynamic openApi = container.addServlet(
+          "OpenApiServlet", new OpenApiServlet());
+        openApi.setLoadOnStartup(2);
+        openApi.addMapping("/openapi.json", "/openapi.yaml", "/swagger-ui");
+        logger.warn("OpenApiServlet registered at /openapi.json, 
/openapi.yaml, /swagger-ui");
+    }
+
 }
diff --git 
a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/OpenApiServlet.java
 
b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/OpenApiServlet.java
new file mode 100644
index 0000000000..2eccd5aed7
--- /dev/null
+++ 
b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/OpenApiServlet.java
@@ -0,0 +1,81 @@
+/*
+ * 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 userguide.springboot.configuration;
+
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.axis2.context.ConfigurationContext;
+import org.apache.axis2.openapi.OpenApiModule;
+import org.apache.axis2.openapi.SwaggerUIHandler;
+import org.apache.axis2.transport.http.AxisServlet;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.IOException;
+
+/**
+ * Servlet that serves OpenAPI documentation endpoints by delegating to
+ * the Axis2 OpenAPI module's SwaggerUIHandler.
+ *
+ * Registered directly in Axis2WebAppInitializer at:
+ *   /openapi.json  - OpenAPI 3.0.1 specification (JSON)
+ *   /openapi.yaml  - OpenAPI 3.0.1 specification (YAML)
+ *   /swagger-ui    - Interactive Swagger UI documentation
+ */
+public class OpenApiServlet extends HttpServlet {
+
+    private static final Log log = LogFactory.getLog(OpenApiServlet.class);
+
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse 
response) throws IOException {
+        String uri = request.getRequestURI();
+        log.info("OpenApiServlet.doGet() called for URI: " + uri);
+
+        ConfigurationContext configContext = (ConfigurationContext)
+                
getServletContext().getAttribute(AxisServlet.CONFIGURATION_CONTEXT);
+        if (configContext == null) {
+            log.warn("AxisServlet ConfigurationContext not found in 
ServletContext");
+            response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, 
"OpenAPI module not available");
+            return;
+        }
+
+        SwaggerUIHandler handler = 
OpenApiModule.getSwaggerUIHandler(configContext);
+        if (handler == null) {
+            log.warn("OpenAPI SwaggerUIHandler not found — ensure openapi 
module is in WEB-INF/modules");
+            response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, 
"OpenAPI module not initialized");
+            return;
+        }
+
+        try {
+            if (uri.endsWith("/openapi.json")) {
+                handler.handleOpenApiJsonRequest(request, response);
+            } else if (uri.endsWith("/openapi.yaml")) {
+                handler.handleOpenApiYamlRequest(request, response);
+            } else if (uri.contains("/swagger-ui")) {
+                handler.handleSwaggerUIRequest(request, response);
+            } else {
+                response.sendError(HttpServletResponse.SC_NOT_FOUND);
+            }
+        } catch (Exception e) {
+            log.error("OpenApiServlet error handling " + uri + ": " + 
e.getMessage(), e);
+            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 
e.getMessage());
+        }
+    }
+}
diff --git 
a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java
 
b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java
index ba74dbc1e4..f2524f6d4a 100644
--- 
a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java
+++ 
b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java
@@ -55,6 +55,13 @@ public class HTTPPostOnlyRejectionFilter extends 
OncePerRequestFilter {
         
         logger.trace(logPrefix + "starting ... ");
         
+        String uri = request.getRequestURI();
+        boolean isOpenApiPath = uri.endsWith("/openapi.json") || 
uri.endsWith("/openapi.yaml") || uri.endsWith("/swagger-ui");
+        if (isOpenApiPath) {
+            filterChain.doFilter(request, response);
+            return;
+        }
+
         if (!request.getMethod().equals("POST")) {
 
            String ip = "unknown";
diff --git 
a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java
 
b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java
index 4b6e818a9a..59448a68a8 100644
--- 
a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java
+++ 
b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java
@@ -55,6 +55,10 @@ public class JWTAuthenticationFilter extends 
AbstractAuthenticationProcessingFil
 
     @Override
     protected boolean requiresAuthentication(HttpServletRequest request, 
HttpServletResponse response) {
+        String uri = request.getRequestURI();
+        if (uri.endsWith("/openapi.json") || uri.endsWith("/openapi.yaml") || 
uri.endsWith("/swagger-ui")) {
+            return false; // OpenAPI documentation endpoints are public
+        }
         return true;
     }
 

Reply via email to