diff --git a/launcher-impl/microprofile/openapi/pom.xml b/launcher-impl/microprofile/openapi/pom.xml
index 4a4e243..10dfbb3 100644
--- a/launcher-impl/microprofile/openapi/pom.xml
+++ b/launcher-impl/microprofile/openapi/pom.xml
@@ -1,6 +1,6 @@
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.8.1
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ 5.8.1
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ 5.8.1
+ test
+
+
+ org.mockito
+ mockito-core
+ 4.0.0
+ test
@@ -47,6 +76,11 @@
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.0.0-M5
+
diff --git a/launcher-impl/microprofile/openapi/src/main/java/com/fujitsu/launcher/microprofile/openapi/OpenApiService.java b/launcher-impl/microprofile/openapi/src/main/java/com/fujitsu/launcher/microprofile/openapi/OpenApiService.java
index 59f4fdb..61b3fa5 100644
--- a/launcher-impl/microprofile/openapi/src/main/java/com/fujitsu/launcher/microprofile/openapi/OpenApiService.java
+++ b/launcher-impl/microprofile/openapi/src/main/java/com/fujitsu/launcher/microprofile/openapi/OpenApiService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019 Fujitsu Limited and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019-2021 Fujitsu Limited and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -17,6 +17,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Set;
+import java.util.regex.Pattern;
import javax.inject.Inject;
@@ -39,7 +40,7 @@
import io.smallrye.openapi.api.OpenApiDocument;
import io.smallrye.openapi.runtime.OpenApiProcessor;
import io.smallrye.openapi.runtime.OpenApiStaticFile;
-import io.smallrye.openapi.runtime.io.OpenApiSerializer.Format;
+import io.smallrye.openapi.runtime.io.Format;
/**
*
* @author Katsuhiro Kunisada
@@ -166,10 +167,10 @@ private boolean isJarToBeScanned(OpenApiConfig config, String entry) {
}
private boolean isClassToBeScanned(OpenApiConfig config, String entry) {
- Set scanClasses = config.scanClasses();
- Set scanPackages = config.scanPackages();
- Set scanExcludeClasses = config.scanExcludeClasses();
- Set scanExcludePackages = config.scanExcludePackages();
+ Pattern scanClasses = config.scanClasses();
+ Pattern scanPackages = config.scanPackages();
+ Pattern scanExcludeClasses = config.scanExcludeClasses();
+ Pattern scanExcludePackages = config.scanExcludePackages();
if (entry == null) {
return false;
@@ -179,16 +180,16 @@ private boolean isClassToBeScanned(OpenApiConfig config, String entry) {
String packageName = getPackageName(fqcn);
boolean ret;
- if (scanClasses.isEmpty() && scanPackages.isEmpty()) {
+ if (scanClasses.pattern().isEmpty() && scanPackages.pattern().isEmpty()) {
ret = true;
- } else if (!scanClasses.isEmpty() && scanPackages.isEmpty()) {
- ret = scanClasses.contains(fqcn);
- } else if (scanClasses.isEmpty() && !scanPackages.isEmpty()) {
- ret = scanPackages.contains(packageName);
+ } else if (!scanClasses.pattern().isEmpty() && scanPackages.pattern().isEmpty()) {
+ ret = scanClasses.matcher(fqcn).matches();
+ } else if (scanClasses.pattern().isEmpty() && !scanPackages.pattern().isEmpty()) {
+ ret = scanPackages.matcher(packageName).matches();
} else {
- ret = scanClasses.contains(fqcn) || scanPackages.contains(packageName);
+ ret = scanClasses.matcher(fqcn).matches() || scanPackages.matcher(packageName).matches();
}
- if (scanExcludeClasses.contains(fqcn) || scanExcludePackages.contains(packageName)) {
+ if (scanExcludeClasses.matcher(fqcn).matches() || scanExcludePackages.matcher(packageName).matches()) {
ret = false;
}
return ret;
diff --git a/launcher-impl/microprofile/openapi/src/main/java/com/fujitsu/launcher/microprofile/openapi/OpenApiServlet.java b/launcher-impl/microprofile/openapi/src/main/java/com/fujitsu/launcher/microprofile/openapi/OpenApiServlet.java
index fafa20c..7d24f99 100644
--- a/launcher-impl/microprofile/openapi/src/main/java/com/fujitsu/launcher/microprofile/openapi/OpenApiServlet.java
+++ b/launcher-impl/microprofile/openapi/src/main/java/com/fujitsu/launcher/microprofile/openapi/OpenApiServlet.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019 Fujitsu Limited and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019-2021 Fujitsu Limited and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -10,6 +10,9 @@
package com.fujitsu.launcher.microprofile.openapi;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
@@ -17,45 +20,81 @@
import javax.servlet.http.HttpServletResponse;
import io.smallrye.openapi.api.OpenApiDocument;
+import io.smallrye.openapi.runtime.io.Format;
import io.smallrye.openapi.runtime.io.OpenApiSerializer;
-import io.smallrye.openapi.runtime.io.OpenApiSerializer.Format;
+
+import org.glassfish.jersey.message.internal.AcceptableMediaType;
+import org.glassfish.jersey.message.internal.HttpHeaderReader;
+
+import java.text.ParseException;
+
+import javax.ws.rs.core.MediaType;
/**
*
* @author Takahiro Nagao
* @author Katsuhiro Kunisada
+ * @author Koki Kosaka
*/
@SuppressWarnings("serial")
@WebServlet
public class OpenApiServlet extends HttpServlet {
- public static final String MEDIA_TYPE_YAML = "text/plain";
- public static final String MEDIA_TYPE_JSON = "application/json";
+ public static final Map ACCEPTED_TYPES = new HashMap<>();
+
+ static {
+ ACCEPTED_TYPES.put(Format.YAML, MediaType.TEXT_PLAIN);
+ ACCEPTED_TYPES.put(Format.JSON, MediaType.APPLICATION_JSON);
+ }
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
- Format format = Format.YAML;
- String type = MEDIA_TYPE_YAML;
+ Format format = getResponseFormat(request);
+ if (format != null) {
+ String oai = OpenApiSerializer.serialize(OpenApiDocument.INSTANCE.get(), format);
+ response.setContentType(ACCEPTED_TYPES.get(format));
+ response.getWriter().write(oai);
+ response.setStatus(HttpServletResponse.SC_OK);
+ } else {
+ response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE);
+ }
+ }
- if (isJson(request)) {
- format = Format.JSON;
- type = MEDIA_TYPE_JSON;
+ protected Format getResponseFormat(HttpServletRequest request) {
+ try {
+ Format format = parseFormatQueryParameter(request);
+ if (format != null) return format;
+ return parseAcceptHeader(request);
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
}
+ }
- String oai = OpenApiSerializer.serialize(OpenApiDocument.INSTANCE.get(), format);
- response.getWriter().write(oai);
- response.setContentType(type);
- response.setStatus(200);
+ private Format parseFormatQueryParameter(HttpServletRequest request) {
+ String formatParam = request.getParameter("format");
+ if (formatParam != null) {
+ for (Format f : Format.values()) {
+ if (f.name().equalsIgnoreCase(formatParam)) return f;
+ }
+ }
+ return null;
}
- private boolean isJson(HttpServletRequest request) {
- String accept = request.getHeader("Accept");
- if (accept != null && accept.equals(MEDIA_TYPE_JSON)) {
- return true;
+ private Format parseAcceptHeader(HttpServletRequest request) throws ParseException {
+ String acceptHeader = request.getHeader("Accept");
+ // sorted by quality value
+ List mediaTypes = HttpHeaderReader.readAcceptMediaType(acceptHeader);
+ if (mediaTypes.isEmpty()) {
+ mediaTypes.add(AcceptableMediaType.valueOf(MediaType.WILDCARD_TYPE));
}
- String formatParam = request.getParameter("format");
- if (formatParam != null && formatParam.equals("json")) {
- return true;
+
+ for (AcceptableMediaType mediaType : mediaTypes) {
+ if (mediaType.isCompatible(MediaType.TEXT_PLAIN_TYPE)) {
+ return Format.YAML;
+ }
+ if (mediaType.isCompatible(MediaType.APPLICATION_JSON_TYPE)) {
+ return Format.JSON;
+ }
}
- return false;
+ return null;
}
}
diff --git a/launcher-impl/microprofile/openapi/src/test/java/com/fujitsu/launcher/microprofile/openapi/OpenApiServletTest.java b/launcher-impl/microprofile/openapi/src/test/java/com/fujitsu/launcher/microprofile/openapi/OpenApiServletTest.java
new file mode 100644
index 0000000..d7e73dc
--- /dev/null
+++ b/launcher-impl/microprofile/openapi/src/test/java/com/fujitsu/launcher/microprofile/openapi/OpenApiServletTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2021 Fujitsu Limited and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+
+package com.fujitsu.launcher.microprofile.openapi;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.util.stream.Stream;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import io.smallrye.openapi.runtime.io.Format;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class OpenApiServletTest {
+
+ HttpServletRequest mockRequest = mock(HttpServletRequest.class);
+ HttpServletResponse mockResponse = mock(HttpServletResponse.class);
+
+ OpenApiServlet servlet = spy(new OpenApiServlet());
+
+ @ParameterizedTest
+ @MethodSource({"provideOnlyAcceptHeader", "provideOnlyFormatQuery", "provideFormatQueryAndAcceptHeader"})
+ public void testGetResponseFormat(String format, String acceptHeader, Format expected) {
+ when(mockRequest.getParameter("format")).thenReturn(format);
+ when(mockRequest.getHeader("Accept")).thenReturn(acceptHeader);
+ Format result = servlet.getResponseFormat(mockRequest);
+ assertEquals(result, expected);
+ }
+
+ private static Stream provideOnlyAcceptHeader() {
+ return Stream.of(
+ // one value
+ Arguments.of(null, "", Format.YAML),
+ Arguments.of(null, "text/plain", Format.YAML),
+ Arguments.of(null, "application/json", Format.JSON),
+ Arguments.of(null, "*/*", Format.YAML),
+ Arguments.of(null, "text/*", Format.YAML),
+ Arguments.of(null, "application/*", Format.JSON),
+ Arguments.of(null, "hoge/hoge", null),
+
+ // two value
+ Arguments.of(null, "text/plain, application/json", Format.YAML),
+ Arguments.of(null, "application/json, text/plain", Format.JSON),
+ Arguments.of(null, "text/plain;q=0.9, application/json", Format.JSON),
+ Arguments.of(null, "application/json;q=0.9, text/plain", Format.YAML),
+
+ Arguments.of(null, "*/*, application/json", Format.JSON),
+ Arguments.of(null, "text/*, application/json", Format.JSON),
+ Arguments.of(null, "application/*, text/plain", Format.YAML),
+ Arguments.of(null, "text/*, application/json;q=0.9", Format.YAML),
+ Arguments.of(null, "application/*, text/plain;q=0.9", Format.JSON),
+
+ // three value
+ Arguments.of(null, "*/*, application/*, text/plain", Format.YAML),
+ Arguments.of(null, "*/*, application/*, text/plain;q=0.9", Format.JSON),
+ Arguments.of(null, "*/*, application/*;q=0.9, text/plain;q=0.8", Format.YAML)
+ );
+ }
+
+ private static Stream provideOnlyFormatQuery() {
+ return Stream.of(
+ // one value
+ Arguments.of("YAML", null, Format.YAML),
+ Arguments.of("JSON", null, Format.JSON),
+ Arguments.of("yaml", null, Format.YAML),
+ Arguments.of("json", null, Format.JSON),
+ Arguments.of("hoge", null, Format.YAML),
+ Arguments.of(null, null, Format.YAML)
+ );
+ }
+
+ private static Stream provideFormatQueryAndAcceptHeader() {
+ return Stream.of(
+ Arguments.of("YAML", "application/json", Format.YAML),
+ Arguments.of("JSON", "text/plain", Format.JSON),
+ Arguments.of("hoge", "application/json", Format.JSON)
+ );
+ }
+
+ @Test
+ public void testSendError406() throws IOException {
+ doReturn(null).when(servlet).getResponseFormat(mockRequest);
+ servlet.doGet(mockRequest, mockResponse);
+ verify(mockResponse, times(1)).sendError(406);
+ }
+
+ @Test
+ public void testThrowRuntimeException() {
+ when(mockRequest.getParameter("format")).thenReturn(null);
+ when(mockRequest.getHeader("Accept")).thenReturn("application/json:q=0.4"); //colon
+ assertThrows(RuntimeException.class, () -> servlet.getResponseFormat(mockRequest));
+ }
+
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 17bf88d..6526fbe 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,7 +30,7 @@
3.1
1.2.2
3.0
- 1.1.2
+ 2.0
1.3.1
1.3.4
5.1.0
@@ -44,7 +44,7 @@
3.1.1
3.3.0
3.0.3
- 1.0.2
+ 2.1.15
1.3.2
2.33
2.9.4
@@ -285,7 +285,12 @@
io.smallrye
- smallrye-open-api-1.1
+ smallrye-open-api-core
+ ${smallrye.openapi.version}
+
+
+ io.smallrye
+ smallrye-open-api-jaxrs
${smallrye.openapi.version}