From 2d5bad879bb3f18fec4fda7d098d516f36bb37b8 Mon Sep 17 00:00:00 2001 From: reta Date: Thu, 4 Feb 2016 16:52:01 -0500 Subject: [PATCH] Allow to use of multiple Swagger configs per servlet using base path descriminator --- .../io/swagger/jaxrs/config/BeanConfig.java | 12 ++ .../jaxrs/config/SwaggerContextService.java | 116 ++++++++++++++++-- .../jaxrs/listing/BaseApiListingResource.java | 45 +++++-- .../io/swagger/SwaggerContextServiceTest.java | 32 +++++ 4 files changed, 187 insertions(+), 18 deletions(-) diff --git a/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/config/BeanConfig.java b/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/config/BeanConfig.java index f94b2cb0b3..4486b7177e 100644 --- a/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/config/BeanConfig.java +++ b/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/config/BeanConfig.java @@ -51,6 +51,16 @@ public class BeanConfig extends AbstractScanner implements Scanner, SwaggerConfi String configId; String contextId; + private boolean usePathBasedConfig = false; + + public boolean isUsePathBasedConfig() { + return usePathBasedConfig; + } + + public void setUsePathBasedConfig(boolean usePathBasedConfig) { + this.usePathBasedConfig = usePathBasedConfig; + } + public String getResourcePackage() { return this.resourcePackage; } @@ -209,6 +219,8 @@ public void setScan(boolean shouldScan) { .withServletConfig(servletConfig) .withSwaggerConfig(this) .withScanner(this) + .withBasePath(getBasePath()) + .withPathBasedConfig(isUsePathBasedConfig()) .initConfig() .initScanner(); } diff --git a/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/config/SwaggerContextService.java b/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/config/SwaggerContextService.java index 0cb93734de..329825854a 100644 --- a/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/config/SwaggerContextService.java +++ b/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/config/SwaggerContextService.java @@ -9,6 +9,8 @@ import javax.servlet.ServletConfig; +import org.apache.commons.lang3.StringUtils; + public class SwaggerContextService { private static Logger LOGGER = LoggerFactory.getLogger(SwaggerContextService.class); @@ -22,6 +24,7 @@ public class SwaggerContextService { public static final String SCANNER_ID_DEFAULT = SCANNER_ID_PREFIX + "default"; public static final String CONTEXT_ID_KEY = "swagger.context.id"; + public static final String USE_PATH_BASED_CONFIG = "swagger.use.path.based.config"; private ServletConfig sc; private String configId; @@ -29,6 +32,24 @@ public class SwaggerContextService { private String scannerId; private Scanner scanner; private String contextId; + private String basePath; + private boolean usePathBasedConfig = false; + + public boolean isUsePathBasedConfig() { + return usePathBasedConfig; + } + + public void setUsePathBasedConfig(boolean usePathBasedConfig) { + this.usePathBasedConfig = usePathBasedConfig; + } + + public void setBasePath(String basePath) { + this.basePath = normalizeBasePath(basePath); + } + + public String getBasePath() { + return basePath; + } public void setScannerId(String scannerId) { this.scannerId = scannerId; @@ -72,6 +93,16 @@ private static boolean isServletConfigAvailable (ServletConfig sc) { return true; } + public SwaggerContextService withBasePath(String basePath) { + this.basePath = normalizeBasePath(basePath); + return this; + } + + public SwaggerContextService withPathBasedConfig(boolean usePathBasedConfig) { + this.usePathBasedConfig = usePathBasedConfig; + return this; + } + public SwaggerContextService withConfigId(String configId) { this.configId = configId; return this; @@ -112,10 +143,19 @@ public SwaggerContextService initConfig(Swagger swagger) { if (isServletConfigAvailable(sc)) { configIdKey = (sc.getInitParameter(CONFIG_ID_KEY) != null) ? CONFIG_ID_PREFIX + sc.getInitParameter(CONFIG_ID_KEY) : null; if (configIdKey == null) { - configIdKey = (sc.getInitParameter(CONTEXT_ID_KEY) != null) ? CONFIG_ID_PREFIX + sc.getInitParameter(CONTEXT_ID_KEY) : CONFIG_ID_DEFAULT; + boolean usePathBasedConfig = Boolean.valueOf(sc.getInitParameter(USE_PATH_BASED_CONFIG)); + if (usePathBasedConfig && StringUtils.isNotBlank(basePath)) { + configIdKey = CONFIG_ID_PREFIX + basePath; + } else { + configIdKey = (sc.getInitParameter(CONTEXT_ID_KEY) != null) ? CONFIG_ID_PREFIX + sc.getInitParameter(CONTEXT_ID_KEY) : CONFIG_ID_DEFAULT; + } } } else { - configIdKey = CONFIG_ID_DEFAULT; + if (isUsePathBasedConfig() && StringUtils.isNotBlank(basePath)) { + configIdKey = CONFIG_ID_PREFIX + basePath; + } else { + configIdKey = CONFIG_ID_DEFAULT; + } } } SwaggerConfig value = (swaggerConfig != null) ? swaggerConfig : null; @@ -142,7 +182,12 @@ private Object getConfigOrSwagger(boolean returnSwagger) { if (isServletConfigAvailable(sc)) { configIdKey = (sc.getInitParameter(CONFIG_ID_KEY) != null) ? CONFIG_ID_PREFIX + sc.getInitParameter(CONFIG_ID_KEY) : null; if (configIdKey == null) { - configIdKey = (sc.getInitParameter(CONTEXT_ID_KEY) != null) ? CONFIG_ID_PREFIX + sc.getInitParameter(CONTEXT_ID_KEY) : CONFIG_ID_DEFAULT; + boolean usePathBasedConfig = Boolean.valueOf(sc.getInitParameter(USE_PATH_BASED_CONFIG)); + if (usePathBasedConfig && StringUtils.isNotBlank(basePath)) { + configIdKey = CONFIG_ID_PREFIX + basePath; + } else { + configIdKey = (sc.getInitParameter(CONTEXT_ID_KEY) != null) ? CONFIG_ID_PREFIX + sc.getInitParameter(CONTEXT_ID_KEY) : CONFIG_ID_DEFAULT; + } } } else { configIdKey = CONFIG_ID_DEFAULT; @@ -179,10 +224,19 @@ public SwaggerContextService updateSwagger(Swagger swagger) { if (isServletConfigAvailable(sc)) { configIdKey = (sc.getInitParameter(CONFIG_ID_KEY) != null) ? CONFIG_ID_PREFIX + sc.getInitParameter(CONFIG_ID_KEY) : null; if (configIdKey == null) { - configIdKey = (sc.getInitParameter(CONTEXT_ID_KEY) != null) ? CONFIG_ID_PREFIX + sc.getInitParameter(CONTEXT_ID_KEY) : CONFIG_ID_DEFAULT; + boolean usePathBasedConfig = Boolean.valueOf(sc.getInitParameter(USE_PATH_BASED_CONFIG)); + if (usePathBasedConfig && StringUtils.isNotBlank(basePath)) { + configIdKey = CONFIG_ID_PREFIX + basePath; + } else { + configIdKey = (sc.getInitParameter(CONTEXT_ID_KEY) != null) ? CONFIG_ID_PREFIX + sc.getInitParameter(CONTEXT_ID_KEY) : CONFIG_ID_DEFAULT; + } } } else { - configIdKey = CONFIG_ID_DEFAULT; + if (isUsePathBasedConfig() && StringUtils.isNotBlank(basePath)) { + configIdKey = CONFIG_ID_PREFIX + basePath; + } else { + configIdKey = CONFIG_ID_DEFAULT; + } } } if (swagger != null) { @@ -202,10 +256,19 @@ public SwaggerContextService initScanner() { if (isServletConfigAvailable(sc)) { scannerIdKey = (sc.getInitParameter(SCANNER_ID_KEY) != null) ? SCANNER_ID_PREFIX + sc.getInitParameter(SCANNER_ID_KEY) : null; if (scannerIdKey == null) { - scannerIdKey = (sc.getInitParameter(CONTEXT_ID_KEY) != null) ? SCANNER_ID_PREFIX + sc.getInitParameter(CONTEXT_ID_KEY) : SCANNER_ID_DEFAULT; + boolean usePathBasedConfig = Boolean.valueOf(sc.getInitParameter(USE_PATH_BASED_CONFIG)); + if (usePathBasedConfig && StringUtils.isNotBlank(basePath)) { + scannerIdKey = SCANNER_ID_PREFIX + basePath; + } else { + scannerIdKey = (sc.getInitParameter(CONTEXT_ID_KEY) != null) ? SCANNER_ID_PREFIX + sc.getInitParameter(CONTEXT_ID_KEY) : SCANNER_ID_DEFAULT; + } } } else { - scannerIdKey = SCANNER_ID_DEFAULT; + if (isUsePathBasedConfig() && StringUtils.isNotBlank(basePath)) { + scannerIdKey = SCANNER_ID_PREFIX + basePath; + } else { + scannerIdKey = SCANNER_ID_DEFAULT; + } } } Scanner value = (scanner != null) ? scanner : new DefaultJaxrsScanner(); @@ -233,7 +296,12 @@ public Scanner getScanner() { if (isServletConfigAvailable(sc)) { scannerIdKey = (sc.getInitParameter(SCANNER_ID_KEY) != null) ? SCANNER_ID_PREFIX + sc.getInitParameter(SCANNER_ID_KEY) : null; if (scannerIdKey == null) { - scannerIdKey = (sc.getInitParameter(CONTEXT_ID_KEY) != null) ? SCANNER_ID_PREFIX + sc.getInitParameter(CONTEXT_ID_KEY) : SCANNER_ID_DEFAULT; + boolean usePathBasedConfig = Boolean.valueOf(sc.getInitParameter(USE_PATH_BASED_CONFIG)); + if (usePathBasedConfig && StringUtils.isNotBlank(basePath)) { + scannerIdKey = SCANNER_ID_PREFIX + basePath; + } else { + scannerIdKey = (sc.getInitParameter(CONTEXT_ID_KEY) != null) ? SCANNER_ID_PREFIX + sc.getInitParameter(CONTEXT_ID_KEY) : SCANNER_ID_DEFAULT; + } } value = (Scanner) sc.getServletContext().getAttribute(scannerIdKey); } else { @@ -250,6 +318,16 @@ public Scanner getScanner() { return ScannerFactory.getScanner(); } + public static boolean isUsePathBasedConfigInitParamDefined(ServletConfig sc) { + if (!isServletConfigAvailable(sc)) return false; + String key = sc.getInitParameter(USE_PATH_BASED_CONFIG); + if (key != null){ + return true; + } else { + return (sc.getInitParameter(CONTEXT_ID_KEY) != null) ? true : false; + } + } + public static boolean isScannerIdInitParamDefined(ServletConfig sc) { if (!isServletConfigAvailable(sc)) return false; String key = sc.getInitParameter(SCANNER_ID_KEY); @@ -289,4 +367,26 @@ public static String getConfigIdFromInitParam(ServletConfig sc) { return sc.getInitParameter(CONTEXT_ID_KEY); } } + + /** + * Normalize base path to the canonical form by adding trailing and leading slashes + * @param basePath base path to normalize + * @return normalized base path + */ + private static String normalizeBasePath(final String basePath) { + if (basePath == null) { + return basePath; + } + + String normalizedBasePath = basePath.trim(); + if (!normalizedBasePath.startsWith("/")) { + normalizedBasePath = "/" + normalizedBasePath; + } + + if (!normalizedBasePath.endsWith("/")) { + normalizedBasePath = normalizedBasePath + "/"; + } + + return normalizedBasePath; + } } diff --git a/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/listing/BaseApiListingResource.java b/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/listing/BaseApiListingResource.java index a7d16e736b..21d1285afd 100644 --- a/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/listing/BaseApiListingResource.java +++ b/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/listing/BaseApiListingResource.java @@ -37,13 +37,20 @@ public abstract class BaseApiListingResource { private static Logger LOGGER = LoggerFactory.getLogger(BaseApiListingResource.class); - private static synchronized Swagger scan(Application app, ServletContext context, ServletConfig sc) { + private static synchronized Swagger scan(Application app, ServletContext context, ServletConfig sc, UriInfo uriInfo) { Swagger swagger = null; - SwaggerContextService ctxService = new SwaggerContextService().withServletConfig(sc); + + SwaggerContextService ctxService = new SwaggerContextService() + .withServletConfig(sc) + .withBasePath(getBasePath(uriInfo)); + Scanner scanner = ctxService.getScanner(); if (scanner != null) { SwaggerSerializers.setPrettyPrint(scanner.getPrettyPrint()); - swagger = new SwaggerContextService().withServletConfig(sc).getSwagger(); + swagger = new SwaggerContextService() + .withServletConfig(sc) + .withBasePath(getBasePath(uriInfo)) + .getSwagger(); Set> classes; if (scanner instanceof JaxrsScanner) { JaxrsScanner jaxrsScanner = (JaxrsScanner) scanner; @@ -65,13 +72,18 @@ private static synchronized Swagger scan(Application app, ServletContext context LOGGER.debug("no configurator"); } } - new SwaggerContextService().withServletConfig(sc).updateSwagger(swagger); + new SwaggerContextService() + .withServletConfig(sc) + .withBasePath(getBasePath(uriInfo)) + .updateSwagger(swagger); } } if (SwaggerContextService.isScannerIdInitParamDefined(sc)) { initializedScanner.put(sc.getServletName() + "_" + SwaggerContextService.getScannerIdFromInitParam(sc), true); } else if (SwaggerContextService.isConfigIdInitParamDefined(sc)) { initializedConfig.put(sc.getServletName() + "_" + SwaggerContextService.getConfigIdFromInitParam(sc), true); + } else if (SwaggerContextService.isUsePathBasedConfigInitParamDefined(sc)) { + initializedConfig.put(sc.getServletName() + "_" + ctxService.getBasePath(), true); } else { initialized = true; } @@ -85,21 +97,27 @@ private Swagger process( ServletConfig sc, HttpHeaders headers, UriInfo uriInfo) { - Swagger swagger = new SwaggerContextService().withServletConfig(sc).getSwagger(); + SwaggerContextService ctxService = new SwaggerContextService() + .withServletConfig(sc) + .withBasePath(getBasePath(uriInfo)); + + Swagger swagger = ctxService.getSwagger(); synchronized (ApiListingResource.class) { if (SwaggerContextService.isScannerIdInitParamDefined(sc)) { if (!initializedScanner.containsKey(sc.getServletName() + "_" + SwaggerContextService.getScannerIdFromInitParam(sc))) { - swagger = scan(app, servletContext, sc); + swagger = scan(app, servletContext, sc, uriInfo); } } else { if (SwaggerContextService.isConfigIdInitParamDefined(sc)) { if (!initializedConfig.containsKey(sc.getServletName() + "_" + SwaggerContextService.getConfigIdFromInitParam(sc))) { - swagger = scan(app, servletContext, sc); + swagger = scan(app, servletContext, sc, uriInfo); } - } else { - if (!initialized) { - swagger = scan(app, servletContext, sc); + } else if (SwaggerContextService.isUsePathBasedConfigInitParamDefined(sc)) { + if (!initializedConfig.containsKey(sc.getServletName() + "_" + ctxService.getBasePath())) { + swagger = scan(app, servletContext, sc, uriInfo); } + } else if (!initialized) { + swagger = scan(app, servletContext, sc, uriInfo); } } } @@ -186,5 +204,12 @@ private static Map> getHeaders(HttpHeaders headers) { return output; } + private static String getBasePath(UriInfo uriInfo) { + if (uriInfo != null) { + return uriInfo.getBaseUri().getPath(); + } else { + return "/"; + } + } } diff --git a/modules/swagger-jaxrs/src/test/java/io/swagger/SwaggerContextServiceTest.java b/modules/swagger-jaxrs/src/test/java/io/swagger/SwaggerContextServiceTest.java index 20ef7ac89f..6978d7d8e6 100644 --- a/modules/swagger-jaxrs/src/test/java/io/swagger/SwaggerContextServiceTest.java +++ b/modules/swagger-jaxrs/src/test/java/io/swagger/SwaggerContextServiceTest.java @@ -50,6 +50,18 @@ void initMock() { bc.setDescription("Bean Config test 2"); beanConfigScanner2 = bc; } + + void stubWithPathBasedConfigInitParam() { + + when(servletContext1.getAttribute(SCANNER_ID_PREFIX + "/url1")).thenReturn(beanConfigScanner1); + when(servletContext2.getAttribute(SCANNER_ID_PREFIX + "/url2")).thenReturn(beanConfigScanner2); + + when(servletConfig1.getServletContext()).thenReturn(servletContext1); + when(servletConfig2.getServletContext()).thenReturn(servletContext2); + + when(servletConfig1.getInitParameter(USE_PATH_BASED_CONFIG)).thenReturn("true"); + when(servletConfig2.getInitParameter(USE_PATH_BASED_CONFIG)).thenReturn("true"); + } private void stubWithInitParam() { when(servletContext1.getAttribute(SCANNER_ID_PREFIX + "test.1")).thenReturn(beanConfigScanner1); @@ -281,4 +293,24 @@ public void initConfigViaContextParamSwagger() { } + @Test(description = "should add SwaggerConfig to SwaggerConfigLocator map with keys path-based keys") + public void initializeAndGetConfigBasedOnPath() { + stubWithPathBasedConfigInitParam(); + + new SwaggerContextService() + .withServletConfig(servletConfig1) + .withBasePath("/url1") + .initConfig(); + + new SwaggerContextService() + .withServletConfig(servletConfig2) + .withBasePath("url2") + .initConfig(); + + assertTrue(SwaggerConfigLocator.getInstance().getConfig(CONFIG_ID_PREFIX + "/url1/") instanceof WebXMLReader); + assertTrue(SwaggerConfigLocator.getInstance().getConfig(CONFIG_ID_PREFIX + "/url2/") instanceof WebXMLReader); + + verify(servletConfig1, times(1)).getInitParameter(eq(USE_PATH_BASED_CONFIG)); + verify(servletConfig2, times(1)).getInitParameter(eq(USE_PATH_BASED_CONFIG)); + } }