Skip to content

Commit 9fee3fc

Browse files
Wire axis2-openapi module into springbootdemo samples
Adds the missing HTTP routing layer so the OpenAPI endpoints are reachable in both the Tomcat 11 and WildFly springbootdemo deployments. Changes per sample: - pom.xml: add axis2-openapi dependency - axis2.xml: add <module ref="openapi"/> - OpenApiController: new Spring @controller routing GET /openapi.json, /openapi.yaml, /swagger-ui to SwaggerUIHandler; retrieves ConfigurationContext from ServletContext via AxisServlet.CONFIGURATION_CONTEXT - Axis2Application: add @order(2) OpenAPI filter chain that allows unauthenticated GET requests to the three OpenAPI paths, bypassing the HTTPPostOnlyRejectionFilter and JWT auth that protects /services/*; bump login chain from @order(1) to @order(3) accordingly Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 4503870 commit 9fee3fc

8 files changed

Lines changed: 264 additions & 4 deletions

File tree

modules/samples/userguide/src/userguide/springbootdemo-tomcat11/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,11 @@
230230
<artifactId>axis2-jaxws</artifactId>
231231
<version>2.0.1-SNAPSHOT</version>
232232
</dependency>
233+
<dependency>
234+
<groupId>org.apache.axis2</groupId>
235+
<artifactId>axis2-openapi</artifactId>
236+
<version>2.0.1-SNAPSHOT</version>
237+
</dependency>
233238
<dependency>
234239
<groupId>org.apache.neethi</groupId>
235240
<artifactId>neethi</artifactId>

modules/samples/userguide/src/userguide/springbootdemo-tomcat11/resources-axis2/conf/axis2.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@
258258
<!-- commented out for the Axis2 spring boot demo that uses JSON -->
259259
<!-- <module ref="addressing"/> -->
260260

261+
<!-- OpenAPI/Swagger documentation module -->
262+
<module ref="openapi"/>
263+
261264
<!--Configuring module , providing parameters for modules whether they refer or not-->
262265
<!--<moduleConfig name="addressing">-->
263266
<!--<parameter name="addressingPara">N/A</parameter>-->

modules/samples/userguide/src/userguide/springbootdemo-tomcat11/src/main/java/userguide/springboot/Axis2Application.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,11 +347,34 @@ public void writeHeaders(HttpServletRequest request, HttpServletResponse respons
347347
return headerFilter;
348348
}
349349

350-
// these two chains are a binary choice.
350+
// OpenAPI documentation endpoints — GET requests, no auth required
351+
class OpenApiRequestMatcher implements RequestMatcher {
352+
private static final String[] OPENAPI_PATHS = {"/openapi.json", "/openapi.yaml", "/swagger-ui"};
353+
354+
@Override
355+
public boolean matches(HttpServletRequest request) {
356+
String uri = request.getRequestURI();
357+
for (String path : OPENAPI_PATHS) {
358+
if (uri.equals(path) || uri.startsWith(path + "/")) {
359+
return true;
360+
}
361+
}
362+
return false;
363+
}
364+
}
365+
366+
@Bean(name = "springSecurityFilterChainOpenApi")
367+
@Order(2)
368+
public SecurityFilterChain springSecurityFilterChainOpenApi() throws Exception {
369+
// Only header filter — no POST restriction, no JWT, no login processing
370+
return new DefaultSecurityFilterChain(new OpenApiRequestMatcher(), headerWriterFilter());
371+
}
372+
373+
// these two chains are a binary choice.
351374
// A login url will match, otherwise invoke jwtAuthenticationFilter
352375

353376
@Bean(name = "springSecurityFilterChainLogin")
354-
@Order(1)
377+
@Order(3)
355378
public SecurityFilterChain springSecurityFilterChainLogin() throws ServletException, Exception {
356379
String logPrefix = "GenericAccessDecisionManager.springSecurityFilterChain , ";
357380
logger.debug(logPrefix + "inside main filter config ...");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package userguide.springboot.configuration;
20+
21+
import jakarta.servlet.ServletContext;
22+
import jakarta.servlet.http.HttpServletRequest;
23+
import jakarta.servlet.http.HttpServletResponse;
24+
import org.apache.axis2.context.ConfigurationContext;
25+
import org.apache.axis2.openapi.OpenApiModule;
26+
import org.apache.axis2.openapi.SwaggerUIHandler;
27+
import org.apache.axis2.transport.http.AxisServlet;
28+
import org.apache.commons.logging.Log;
29+
import org.apache.commons.logging.LogFactory;
30+
import org.springframework.beans.factory.annotation.Autowired;
31+
import org.springframework.stereotype.Controller;
32+
import org.springframework.web.bind.annotation.GetMapping;
33+
34+
/**
35+
* Routes OpenAPI documentation requests to the Axis2 OpenAPI module handlers.
36+
*
37+
* The axis2-openapi module stores its handlers in ConfigurationContext during
38+
* module init. AxisServlet stores ConfigurationContext in ServletContext under
39+
* the key AxisServlet.CONFIGURATION_CONTEXT ("CONFIGURATION_CONTEXT"). This
40+
* controller bridges Spring MVC routing to those handlers, enabling the standard
41+
* OpenAPI endpoints alongside the Axis2 /services/* path.
42+
*
43+
* Endpoints served:
44+
* GET /openapi.json - OpenAPI 3.0.1 specification (JSON)
45+
* GET /openapi.yaml - OpenAPI 3.0.1 specification (YAML)
46+
* GET /swagger-ui - Interactive Swagger UI documentation page
47+
*/
48+
@Controller
49+
public class OpenApiController {
50+
51+
private static final Log log = LogFactory.getLog(OpenApiController.class);
52+
53+
@Autowired
54+
private ServletContext servletContext;
55+
56+
private SwaggerUIHandler getHandler() {
57+
ConfigurationContext configContext = (ConfigurationContext)
58+
servletContext.getAttribute(AxisServlet.CONFIGURATION_CONTEXT);
59+
if (configContext == null) {
60+
log.warn("AxisServlet ConfigurationContext not found in ServletContext — AxisServlet may not have started yet");
61+
return null;
62+
}
63+
SwaggerUIHandler handler = OpenApiModule.getSwaggerUIHandler(configContext);
64+
if (handler == null) {
65+
log.warn("OpenAPI module not initialized — ensure axis2-openapi is on the classpath and <module ref=\"openapi\"/> is in axis2.xml");
66+
}
67+
return handler;
68+
}
69+
70+
@GetMapping("/openapi.json")
71+
public void openApiJson(HttpServletRequest request, HttpServletResponse response) throws Exception {
72+
SwaggerUIHandler handler = getHandler();
73+
if (handler == null) {
74+
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "OpenAPI module not available");
75+
return;
76+
}
77+
handler.handleOpenApiJsonRequest(request, response);
78+
}
79+
80+
@GetMapping("/openapi.yaml")
81+
public void openApiYaml(HttpServletRequest request, HttpServletResponse response) throws Exception {
82+
SwaggerUIHandler handler = getHandler();
83+
if (handler == null) {
84+
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "OpenAPI module not available");
85+
return;
86+
}
87+
handler.handleOpenApiYamlRequest(request, response);
88+
}
89+
90+
@GetMapping("/swagger-ui")
91+
public void swaggerUi(HttpServletRequest request, HttpServletResponse response) throws Exception {
92+
SwaggerUIHandler handler = getHandler();
93+
if (handler == null) {
94+
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "OpenAPI module not available");
95+
return;
96+
}
97+
handler.handleSwaggerUIRequest(request, response);
98+
}
99+
}

modules/samples/userguide/src/userguide/springbootdemo/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,11 @@
230230
<artifactId>axis2-jaxws</artifactId>
231231
<version>2.0.1-SNAPSHOT</version>
232232
</dependency>
233+
<dependency>
234+
<groupId>org.apache.axis2</groupId>
235+
<artifactId>axis2-openapi</artifactId>
236+
<version>2.0.1-SNAPSHOT</version>
237+
</dependency>
233238
<dependency>
234239
<groupId>org.apache.neethi</groupId>
235240
<artifactId>neethi</artifactId>

modules/samples/userguide/src/userguide/springbootdemo/resources-axis2/conf/axis2.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@
258258
<!-- commented out for the Axis2 spring boot demo that uses JSON -->
259259
<!-- <module ref="addressing"/> -->
260260

261+
<!-- OpenAPI/Swagger documentation module -->
262+
<module ref="openapi"/>
263+
261264
<!--Configuring module , providing parameters for modules whether they refer or not-->
262265
<!--<moduleConfig name="addressing">-->
263266
<!--<parameter name="addressingPara">N/A</parameter>-->

modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/Axis2Application.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,11 +341,34 @@ public void writeHeaders(HttpServletRequest request, HttpServletResponse respons
341341
return headerFilter;
342342
}
343343

344-
// these two chains are a binary choice.
344+
// OpenAPI documentation endpoints — GET requests, no auth required
345+
class OpenApiRequestMatcher implements RequestMatcher {
346+
private static final String[] OPENAPI_PATHS = {"/openapi.json", "/openapi.yaml", "/swagger-ui"};
347+
348+
@Override
349+
public boolean matches(HttpServletRequest request) {
350+
String uri = request.getRequestURI();
351+
for (String path : OPENAPI_PATHS) {
352+
if (uri.equals(path) || uri.startsWith(path + "/")) {
353+
return true;
354+
}
355+
}
356+
return false;
357+
}
358+
}
359+
360+
@Bean(name = "springSecurityFilterChainOpenApi")
361+
@Order(2)
362+
public SecurityFilterChain springSecurityFilterChainOpenApi() throws Exception {
363+
// Only header filter — no POST restriction, no JWT, no login processing
364+
return new DefaultSecurityFilterChain(new OpenApiRequestMatcher(), headerWriterFilter());
365+
}
366+
367+
// these two chains are a binary choice.
345368
// A login url will match, otherwise invoke jwtAuthenticationFilter
346369

347370
@Bean(name = "springSecurityFilterChainLogin")
348-
@Order(1)
371+
@Order(3)
349372
public SecurityFilterChain springSecurityFilterChainLogin() throws ServletException, Exception {
350373
String logPrefix = "GenericAccessDecisionManager.springSecurityFilterChain , ";
351374
logger.debug(logPrefix + "inside main filter config ...");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package userguide.springboot.configuration;
20+
21+
import jakarta.servlet.ServletContext;
22+
import jakarta.servlet.http.HttpServletRequest;
23+
import jakarta.servlet.http.HttpServletResponse;
24+
import org.apache.axis2.context.ConfigurationContext;
25+
import org.apache.axis2.openapi.OpenApiModule;
26+
import org.apache.axis2.openapi.SwaggerUIHandler;
27+
import org.apache.axis2.transport.http.AxisServlet;
28+
import org.apache.commons.logging.Log;
29+
import org.apache.commons.logging.LogFactory;
30+
import org.springframework.beans.factory.annotation.Autowired;
31+
import org.springframework.stereotype.Controller;
32+
import org.springframework.web.bind.annotation.GetMapping;
33+
34+
/**
35+
* Routes OpenAPI documentation requests to the Axis2 OpenAPI module handlers.
36+
*
37+
* The axis2-openapi module stores its handlers in ConfigurationContext during
38+
* module init. AxisServlet stores ConfigurationContext in ServletContext under
39+
* the key AxisServlet.CONFIGURATION_CONTEXT ("CONFIGURATION_CONTEXT"). This
40+
* controller bridges Spring MVC routing to those handlers, enabling the standard
41+
* OpenAPI endpoints alongside the Axis2 /services/* path.
42+
*
43+
* Endpoints served:
44+
* GET /openapi.json - OpenAPI 3.0.1 specification (JSON)
45+
* GET /openapi.yaml - OpenAPI 3.0.1 specification (YAML)
46+
* GET /swagger-ui - Interactive Swagger UI documentation page
47+
*/
48+
@Controller
49+
public class OpenApiController {
50+
51+
private static final Log log = LogFactory.getLog(OpenApiController.class);
52+
53+
@Autowired
54+
private ServletContext servletContext;
55+
56+
private SwaggerUIHandler getHandler() {
57+
ConfigurationContext configContext = (ConfigurationContext)
58+
servletContext.getAttribute(AxisServlet.CONFIGURATION_CONTEXT);
59+
if (configContext == null) {
60+
log.warn("AxisServlet ConfigurationContext not found in ServletContext — AxisServlet may not have started yet");
61+
return null;
62+
}
63+
SwaggerUIHandler handler = OpenApiModule.getSwaggerUIHandler(configContext);
64+
if (handler == null) {
65+
log.warn("OpenAPI module not initialized — ensure axis2-openapi is on the classpath and <module ref=\"openapi\"/> is in axis2.xml");
66+
}
67+
return handler;
68+
}
69+
70+
@GetMapping("/openapi.json")
71+
public void openApiJson(HttpServletRequest request, HttpServletResponse response) throws Exception {
72+
SwaggerUIHandler handler = getHandler();
73+
if (handler == null) {
74+
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "OpenAPI module not available");
75+
return;
76+
}
77+
handler.handleOpenApiJsonRequest(request, response);
78+
}
79+
80+
@GetMapping("/openapi.yaml")
81+
public void openApiYaml(HttpServletRequest request, HttpServletResponse response) throws Exception {
82+
SwaggerUIHandler handler = getHandler();
83+
if (handler == null) {
84+
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "OpenAPI module not available");
85+
return;
86+
}
87+
handler.handleOpenApiYamlRequest(request, response);
88+
}
89+
90+
@GetMapping("/swagger-ui")
91+
public void swaggerUi(HttpServletRequest request, HttpServletResponse response) throws Exception {
92+
SwaggerUIHandler handler = getHandler();
93+
if (handler == null) {
94+
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "OpenAPI module not available");
95+
return;
96+
}
97+
handler.handleSwaggerUIRequest(request, response);
98+
}
99+
}

0 commit comments

Comments
 (0)