From 085ecf10041a9a7ad16b3d5f51ca627d359ae682 Mon Sep 17 00:00:00 2001 From: Thomas Bayer Date: Fri, 2 Jan 2026 17:34:47 +0100 Subject: [PATCH 1/5] refactor: simplify `AzureDnsApiSimulator` by replacing `Outcome.RETURN` with static import and minor cleanup in methods --- .../predic8/membrane/core/cli/RouterCLI.java | 2 +- .../acl/AccessControlInterceptor.java | 2 +- .../apikey/stores/ApiKeyFileStore.java | 2 +- .../session/LDAPUserDataProvider.java | 2 +- .../authentication/session/LoginDialog.java | 6 +- .../xen/XenAuthenticationInterceptor.java | 2 +- .../interceptor/cache/CacheInterceptor.java | 2 +- .../interceptor/jwt/JwtAuthInterceptor.java | 4 +- .../interceptor/jwt/JwtSignInterceptor.java | 2 +- .../interceptor/oauth2/ConsentPageFile.java | 2 +- .../AuthorizationService.java | 6 +- .../DynamicRegistration.java | 2 +- .../MembraneAuthorizationService.java | 2 +- .../MicrosoftEntraIDAuthorizationService.java | 2 +- .../BearerJwtTokenGenerator.java | 2 +- .../oauth2server/LoginDialog2.java | 2 +- .../ValidatorInterceptor.java | 2 +- .../server/WSDLPublisherInterceptor.java | 4 +- .../server/WebServerInterceptor.java | 10 +-- .../session/JwtSessionManager.java | 2 +- .../soap/WebServiceExplorerInterceptor.java | 2 +- .../core/interceptor/stomp/STOMPClient.java | 2 +- .../AbstractTemplateInterceptor.java | 2 +- .../interceptor/xslt/XSLTTransformer.java | 4 +- .../serviceproxy/OpenAPIRecordFactory.java | 4 +- .../core/proxies/AbstractServiceProxy.java | 2 +- .../membrane/core/proxies/SOAPProxy.java | 2 +- .../membrane/core/proxies/SSLProxy.java | 2 +- .../membrane/core/proxies/SSLableProxy.java | 4 +- .../membrane/core/router/Configuration.java | 34 ++++++--- .../core/router/DefaultMainComponents.java | 2 +- .../membrane/core/router/DefaultRouter.java | 73 +++++-------------- .../predic8/membrane/core/router/Router.java | 2 - .../RouterIpResolverInterceptor.java | 2 +- .../jwt/JwtAuthInterceptorTest.java | 50 +++++-------- .../OpenAPIPublisherInterceptorTest.java | 2 +- .../OpenAPIRecordFactoryTest.java | 2 +- .../serviceproxy/OpenAPIRecordTest.java | 2 +- .../openapi/serviceproxy/RewriteTest.java | 2 +- .../XMembraneExtensionSecurityTest.java | 2 +- .../membrane/core/router/DummyTestRouter.java | 11 --- .../membrane/core/router/TestRouter.java | 5 -- .../core/security/JWTSecuritySchemeTest.java | 14 +--- .../core/security/KeyStoreUtilTest.java | 6 +- .../core/transport/ssl/SSLContextTest.java | 2 +- .../core/transport/ssl/acme/AcmeStepTest.java | 2 +- .../interceptor/AcmeRenewTest.java | 2 +- 47 files changed, 117 insertions(+), 182 deletions(-) diff --git a/core/src/main/java/com/predic8/membrane/core/cli/RouterCLI.java b/core/src/main/java/com/predic8/membrane/core/cli/RouterCLI.java index 267f8265d3..cb6e2f054e 100644 --- a/core/src/main/java/com/predic8/membrane/core/cli/RouterCLI.java +++ b/core/src/main/java/com/predic8/membrane/core/cli/RouterCLI.java @@ -161,7 +161,7 @@ private static Router initRouterByYAML(MembraneCommandLine commandLine, String o private static Router initRouterByYAML(String location) throws Exception { var router = new DefaultRouter(); - router.setBaseLocation(location); + router.getConfiguration().setBaseLocation(location); GrammarAutoGenerated grammar = new GrammarAutoGenerated(); BeanRegistryImplementation reg = new BeanRegistryImplementation(router, router, grammar); diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/acl/AccessControlInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/acl/AccessControlInterceptor.java index bab2a95a0e..1cc80da471 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/acl/AccessControlInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/acl/AccessControlInterceptor.java @@ -137,7 +137,7 @@ protected AccessControl parse(String fileName, Router router) { try { reader = factory.createXMLStreamReader( router.getResolverMap().resolve( - ResolverMap.combine(router.getBaseLocation(), fileName))); + ResolverMap.combine(router.getConfiguration().getBaseLocation(), fileName))); AccessControl res = (AccessControl) new AccessControl(router).parse(reader); res.init(router); return res; diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/apikey/stores/ApiKeyFileStore.java b/core/src/main/java/com/predic8/membrane/core/interceptor/apikey/stores/ApiKeyFileStore.java index 2fc453c3bb..4384c9fa9e 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/apikey/stores/ApiKeyFileStore.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/apikey/stores/ApiKeyFileStore.java @@ -61,7 +61,7 @@ public class ApiKeyFileStore implements ApiKeyStore { @Override public void init(Router router) { try { - scopes = readKeyData(readFile(location, router.getResolverMap(), router.getBaseLocation())); + scopes = readKeyData(readFile(location, router.getResolverMap(), router.getConfiguration().getBaseLocation())); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/authentication/session/LDAPUserDataProvider.java b/core/src/main/java/com/predic8/membrane/core/interceptor/authentication/session/LDAPUserDataProvider.java index 4aeaf593b5..6c20ffb7c1 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/authentication/session/LDAPUserDataProvider.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/authentication/session/LDAPUserDataProvider.java @@ -442,7 +442,7 @@ public void init(Router router) { } if (sslParser != null) - CustomSocketFactory.sslContext = new StaticSSLContext(sslParser, router.getResolverMap(), router.getBaseLocation()); + CustomSocketFactory.sslContext = new StaticSSLContext(sslParser, router.getResolverMap(), router.getConfiguration().getBaseLocation()); } public AttributeMap getMap() { diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/authentication/session/LoginDialog.java b/core/src/main/java/com/predic8/membrane/core/interceptor/authentication/session/LoginDialog.java index 27ba7f3696..71ccec4747 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/authentication/session/LoginDialog.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/authentication/session/LoginDialog.java @@ -89,15 +89,15 @@ public void init(Router router) { wsi.init(router); try { // This is only a check if index.html is present - router.getResolverMap().resolve(ResolverMap.combine(router.getBaseLocation(), wsi.getDocBase(), "index.html")).close(); + router.getResolverMap().resolve(ResolverMap.combine(router.getConfiguration().getBaseLocation(), wsi.getDocBase(), "index.html")).close(); } catch (ResourceRetrievalException e) { throw new ConfigurationException(""" Cannot access index.html at: Location base: %s Doc base: %s - """.formatted( router.getBaseLocation(), wsi.getDocBase()),e); + """.formatted( router.getConfiguration().getBaseLocation(), wsi.getDocBase()),e); } catch (IOException e) { - log.error("Cannot access index.html (baseLocation={}, docBase={})" , router.getBaseLocation(), wsi.getDocBase(), e); + log.error("Cannot access index.html (baseLocation={}, docBase={})" , router.getConfiguration().getBaseLocation(), wsi.getDocBase(), e); } } diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/authentication/xen/XenAuthenticationInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/authentication/xen/XenAuthenticationInterceptor.java index 3788863ec7..a2b28ddd5d 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/authentication/xen/XenAuthenticationInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/authentication/xen/XenAuthenticationInterceptor.java @@ -141,7 +141,7 @@ public static class JwtSessionManager implements XenSessionManager { private final SecureRandom random = new SecureRandom(); public void init(Router router) throws Exception { - String key = jwk.get(router.getResolverMap(), router.getBaseLocation()); + String key = jwk.get(router.getResolverMap(), router.getConfiguration().getBaseLocation()); if (key == null || key.isEmpty()) rsaJsonWebKey = generateKey(); else diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/cache/CacheInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/cache/CacheInterceptor.java index 9b67ec25f7..e2207f8531 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/cache/CacheInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/cache/CacheInterceptor.java @@ -103,7 +103,7 @@ public void setDir(String dir) { @Override public void init(Router router) { - dir = ResolverMap.combine(router.getBaseLocation(), dir); + dir = ResolverMap.combine(router.getConfiguration().getBaseLocation(), dir); File d = new File(dir); if (!d.exists()) if (!d.mkdirs()) diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/jwt/JwtAuthInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/jwt/JwtAuthInterceptor.java index a4fc9de313..4c79b1a343 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/jwt/JwtAuthInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/jwt/JwtAuthInterceptor.java @@ -70,12 +70,12 @@ public void init() { if(jwtRetriever == null) jwtRetriever = new HeaderJwtRetriever("Authorization","Bearer"); - jwks.init(router.getResolverMap(),router.getBaseLocation()); + jwks.init(router.getResolverMap(),router.getConfiguration().getBaseLocation()); kidToKey = jwks.getJwks().stream() .map(jwk -> { try { - return new RsaJsonWebKey(mapper.readValue(jwk.getJwk(router.getResolverMap(), router.getBaseLocation(),mapper),Map.class)); + return new RsaJsonWebKey(mapper.readValue(jwk.getJwk(router.getResolverMap(), router.getConfiguration().getBaseLocation(),mapper),Map.class)); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/jwt/JwtSignInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/jwt/JwtSignInterceptor.java index 046c11d9df..75ddd981f0 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/jwt/JwtSignInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/jwt/JwtSignInterceptor.java @@ -52,7 +52,7 @@ public class JwtSignInterceptor extends AbstractInterceptor { public void init() { super.init(); try { - Map params = JsonUtil.parseJson(jwk.get(router.getResolverMap(), router.getBaseLocation())); + Map params = JsonUtil.parseJson(jwk.get(router.getResolverMap(), router.getConfiguration().getBaseLocation())); if (Objects.equals(params.get("p"), DEFAULT_PKEY)) { log.warn(""" \n------------------------------------ DEFAULT JWK IN USE! ------------------------------------ diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/ConsentPageFile.java b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/ConsentPageFile.java index 1b61ff5c33..162b68c0af 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/ConsentPageFile.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/ConsentPageFile.java @@ -47,7 +47,7 @@ public void init(Router router, String url) throws IOException { createDefaults(); return; } - parseFile(getFromUrl(ResolverMap.combine(router.getBaseLocation(),url))); + parseFile(getFromUrl(ResolverMap.combine(router.getConfiguration().getBaseLocation(),url))); } private void parseFile(String consentPageFile) throws IOException { diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/AuthorizationService.java b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/AuthorizationService.java index 2bf8bd7dcf..4ff0a8bad9 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/AuthorizationService.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/AuthorizationService.java @@ -94,13 +94,13 @@ public void init(Router router) throws Exception { log = LoggerFactory.getLogger(this.getClass().getName()); if (isUseJWTForClientAuth()) { - JWSSigner = new JWSSigner(PEMSupport.getInstance().parseKey(getSslParser().getKey().getPrivate().get(router.getResolverMap(), router.getBaseLocation())), - getSslParser().getKey().getCertificates().getFirst().get(router.getResolverMap(), router.getBaseLocation())); + JWSSigner = new JWSSigner(PEMSupport.getInstance().parseKey(getSslParser().getKey().getPrivate().get(router.getResolverMap(), router.getConfiguration().getBaseLocation())), + getSslParser().getKey().getCertificates().getFirst().get(router.getResolverMap(), router.getConfiguration().getBaseLocation())); } setHttpClient(router.getHttpClientFactory().createClient(getHttpClientConfiguration())); if (sslParser != null) - sslContext = new StaticSSLContext(sslParser, router.getResolverMap(), router.getBaseLocation()); + sslContext = new StaticSSLContext(sslParser, router.getResolverMap(), router.getConfiguration().getBaseLocation()); this.router = router; init(); if (!supportsDynamicRegistration()) diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/DynamicRegistration.java b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/DynamicRegistration.java index ac7c9df4c7..1a33317b87 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/DynamicRegistration.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/DynamicRegistration.java @@ -44,7 +44,7 @@ public class DynamicRegistration { public void init(Router router) { this.router = router; if (sslParser != null) - sslContext = new StaticSSLContext(sslParser, router.getResolverMap(), router.getBaseLocation()); + sslContext = new StaticSSLContext(sslParser, router.getResolverMap(), router.getConfiguration().getBaseLocation()); for (Interceptor i : interceptors) i.init(router); client = router.getHttpClientFactory().createClient(httpClientConfiguration); diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/MembraneAuthorizationService.java b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/MembraneAuthorizationService.java index 2ee5d1097d..25d0665367 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/MembraneAuthorizationService.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/MembraneAuthorizationService.java @@ -81,7 +81,7 @@ public void init() throws Exception { } parseSrc(resolve( router.getResolverMap(), - router.getBaseLocation(), + router.getConfiguration().getBaseLocation(), getWellKnownUrl(internalSrc == null ? src : internalSrc))); if(internalSrc != null) { publicAuthorizationEndpoint = src + new URI(authorizationEndpoint).getPath(); diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/MicrosoftEntraIDAuthorizationService.java b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/MicrosoftEntraIDAuthorizationService.java index 0548648de0..2a82ed2926 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/MicrosoftEntraIDAuthorizationService.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/MicrosoftEntraIDAuthorizationService.java @@ -56,7 +56,7 @@ public class MicrosoftEntraIDAuthorizationService extends AuthorizationService { public void init() throws Exception { parseSrc(resolve( router.getResolverMap(), - router.getBaseLocation(), + router.getConfiguration().getBaseLocation(), getWellKnownUrl("https://login.microsoftonline.com/" + tenantId + "/v2.0/"))); adjustScope(); prepareClaimsForLoginUrl(); diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/tokengenerators/BearerJwtTokenGenerator.java b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/tokengenerators/BearerJwtTokenGenerator.java index 13e678f14a..97959f5a95 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/tokengenerators/BearerJwtTokenGenerator.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/tokengenerators/BearerJwtTokenGenerator.java @@ -59,7 +59,7 @@ public void init(Router router) throws Exception { "reference it using .", rsaJsonWebKey.toJson(JsonWebKey.OutputControlLevel.INCLUDE_PRIVATE)); } else { - rsaJsonWebKey = new RsaJsonWebKey(JsonUtil.parseJson(jwk.get(router.getResolverMap(), router.getBaseLocation()))); + rsaJsonWebKey = new RsaJsonWebKey(JsonUtil.parseJson(jwk.get(router.getResolverMap(), router.getConfiguration().getBaseLocation()))); } } diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2server/LoginDialog2.java b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2server/LoginDialog2.java index 088f3ff739..3f1f67b616 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2server/LoginDialog2.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2server/LoginDialog2.java @@ -80,7 +80,7 @@ public LoginDialog2( public void init(Router router) throws Exception { uriFactory = router.getConfiguration().getUriFactory(); wsi.init(router); - router.getResolverMap().resolve(ResolverMap.combine(router.getBaseLocation(), wsi.getDocBase(), "index.html")).close(); + router.getResolverMap().resolve(ResolverMap.combine(router.getConfiguration().getBaseLocation(), wsi.getDocBase(), "index.html")).close(); } diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/ValidatorInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/ValidatorInterceptor.java index ce740bb09f..f0d5101128 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/ValidatorInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/ValidatorInterceptor.java @@ -134,7 +134,7 @@ private static void logIgnoringRefSchemas() { } private @Nullable String getBaseLocation() { - return router == null ? null : router.getBaseLocation(); + return router == null ? null : router.getConfiguration().getBaseLocation(); } @Override diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/server/WSDLPublisherInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/server/WSDLPublisherInterceptor.java index e7e3f3f831..edc234251d 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/server/WSDLPublisherInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/server/WSDLPublisherInterceptor.java @@ -186,7 +186,7 @@ private Outcome handleRequestInternal(final Exchange exc) throws Exception { String resource = null; if (exc.getRequestURI().endsWith("?wsdl") || exc.getRequestURI().endsWith("?WSDL")) { processDocuments(exc); - exc.setResponse(webServerInterceptor.createResponse(router.getResolverMap(), resource = combine(router.getBaseLocation(), wsdl))); + exc.setResponse(webServerInterceptor.createResponse(router.getResolverMap(), resource = combine(router.getConfiguration().getBaseLocation(), wsdl))); exc.getResponse().getHeader().setContentType(TEXT_XML); } if (exc.getRequestURI().contains("?xsd=")) { @@ -209,7 +209,7 @@ private Outcome handleRequestInternal(final Exchange exc) throws Exception { if (resource != null) { WSDLInterceptor wi = new WSDLInterceptor(); wi.setRewriteEndpoint(false); - wi.setPathRewriter(new RelativePathRewriter(exc, combine(router.getBaseLocation(), wsdl))); + wi.setPathRewriter(new RelativePathRewriter(exc, combine(router.getConfiguration().getBaseLocation(), wsdl))); wi.init(router); wi.handleResponse(exc); return RETURN; diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/server/WebServerInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/server/WebServerInterceptor.java index e5c8445005..d508e45b6d 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/server/WebServerInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/server/WebServerInterceptor.java @@ -115,7 +115,7 @@ public Outcome handleRequest(Exchange exc) { if (uri == null) return ABORT; if (generateIndex) { - if (router.getResolverMap().getChildren(combine(router.getBaseLocation(), docBase, uri)) != null) { + if (router.getResolverMap().getChildren(combine(router.getConfiguration().getBaseLocation(), docBase, uri)) != null) { if (tryToReceiveResource(exc, uri)) return RETURN; if (tryToReceiveResource(exc, uri + "/")) @@ -128,7 +128,7 @@ public Outcome handleRequest(Exchange exc) { try { exc.setTimeReqSent(currentTimeMillis()); - exc.setResponse(createResponse(router.getResolverMap(), combine(router.getBaseLocation(), docBase, uri))); + exc.setResponse(createResponse(router.getResolverMap(), combine(router.getConfiguration().getBaseLocation(), docBase, uri))); exc.setReceived(); exc.setTimeResReceived(currentTimeMillis()); return RETURN; @@ -193,7 +193,7 @@ private boolean tryToReceiveResource(Exchange exc, String uri) { for (String i : index) { Response response = createResponse( router.getResolverMap(), - combine(router.getBaseLocation(), docBase, uri + i) + combine(router.getConfiguration().getBaseLocation(), docBase, uri + i) ); if (!response.isOk()) @@ -208,7 +208,7 @@ private boolean tryToReceiveResource(Exchange exc, String uri) { } private Outcome generateHtmlResponseFromChildren(Exchange exc, String uri) throws FileNotFoundException { - List children = router.getResolverMap().getChildren(combine(router.getBaseLocation(), docBase, uri)); + List children = router.getResolverMap().getChildren(combine(router.getConfiguration().getBaseLocation(), docBase, uri)); if (children == null) { return null; } @@ -288,7 +288,7 @@ private String getAbsolutePathWithSchemePrefix(String path) { } private @NotNull String getNewPath(String path) { - String newPath = combine(router.getBaseLocation(), path); + String newPath = combine(router.getConfiguration().getBaseLocation(), path); if (newPath.endsWith(File.separator + File.separator)) newPath = newPath.substring(0, newPath.length() - 1); if (!newPath.endsWith("/")) diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/session/JwtSessionManager.java b/core/src/main/java/com/predic8/membrane/core/interceptor/session/JwtSessionManager.java index a9161e1b70..548333b165 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/session/JwtSessionManager.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/session/JwtSessionManager.java @@ -73,7 +73,7 @@ will not be compatible with sessions of other (e.g. restarted) instances. To solve this, write the JWK into a file and reference it using . """, rsaJsonWebKey.toJson(INCLUDE_PRIVATE)); } else { - rsaJsonWebKey = new RsaJsonWebKey(JsonUtil.parseJson(jwk.get(router.getResolverMap(), router.getBaseLocation()))); + rsaJsonWebKey = new RsaJsonWebKey(JsonUtil.parseJson(jwk.get(router.getResolverMap(), router.getConfiguration().getBaseLocation()))); } idTokenProvider = new IdTokenProvider(rsaJsonWebKey); diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/soap/WebServiceExplorerInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/soap/WebServiceExplorerInterceptor.java index 5ae1915b62..2f99502055 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/soap/WebServiceExplorerInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/soap/WebServiceExplorerInterceptor.java @@ -95,7 +95,7 @@ private Definitions getParsedWSDL() { if (parsedWSDL != null) return parsedWSDL; WSDLParserContext ctx = new WSDLParserContext(); - ctx.setInput(ResolverMap.combine(router.getBaseLocation(), wsdl)); + ctx.setInput(ResolverMap.combine(router.getConfiguration().getBaseLocation(), wsdl)); return parsedWSDL = getWsdlParser().parse(ctx); } diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/stomp/STOMPClient.java b/core/src/main/java/com/predic8/membrane/core/interceptor/stomp/STOMPClient.java index 79cce77bfd..f5e2ed9e80 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/stomp/STOMPClient.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/stomp/STOMPClient.java @@ -101,7 +101,7 @@ public void init() { super.init(); connectionManager = new ConnectionManager(connectionConfiguration.getKeepAliveTimeout(), router.getTimerManager()); if (sslOutboundParser != null) - sslOutboundProvider = new StaticSSLContext(sslOutboundParser, router.getResolverMap(), router.getBaseLocation()); + sslOutboundProvider = new StaticSSLContext(sslOutboundParser, router.getResolverMap(), router.getConfiguration().getBaseLocation()); } @Override diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/templating/AbstractTemplateInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/templating/AbstractTemplateInterceptor.java index 234f2bbac7..040078f7b4 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/templating/AbstractTemplateInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/templating/AbstractTemplateInterceptor.java @@ -121,7 +121,7 @@ protected String asString(byte[] bytes) { } private String readFromLocation() { - try (InputStream is = getRouter().getResolverMap().resolve(combine(getRouter().getBaseLocation(), location))) { + try (InputStream is = getRouter().getResolverMap().resolve(combine(getRouter().getConfiguration().getBaseLocation(), location))) { return IOUtils.toString(is, charset); // TODO Encoding } catch (Exception e) { throw new ConfigurationException("Could not read template from %s".formatted( location), e); diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/xslt/XSLTTransformer.java b/core/src/main/java/com/predic8/membrane/core/interceptor/xslt/XSLTTransformer.java index 86a2728189..24b851bf49 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/xslt/XSLTTransformer.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/xslt/XSLTTransformer.java @@ -38,11 +38,11 @@ public XSLTTransformer(String styleSheet, final Router router, final int concurr this.styleSheet = styleSheet; log.debug("using {} parallel transformer instances for {}",concurrency, styleSheet); transformers = new ArrayBlockingQueue<>(concurrency); - createOneTransformer(router.getResolverMap(), router.getBaseLocation()); + createOneTransformer(router.getResolverMap(), router.getConfiguration().getBaseLocation()); Thread.ofVirtual().start(() -> { try { for (int i = 1; i < concurrency; i++) - createOneTransformer(router.getResolverMap(), router.getBaseLocation()); + createOneTransformer(router.getResolverMap(), router.getConfiguration().getBaseLocation()); } catch (Exception e) { log.error("Error creating XSLT transformer:", e); } diff --git a/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordFactory.java b/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordFactory.java index 44fc955b06..b48d80d3cd 100644 --- a/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordFactory.java +++ b/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordFactory.java @@ -169,7 +169,7 @@ private OpenAPI parseFromLocation(OpenAPISpec spec) { } private InputStream getInputStreamForLocation(String location) throws ResourceRetrievalException { - return router.getResolverMap().resolve(ResolverMap.combine(router.getBaseLocation(), location)); + return router.getResolverMap().resolve(ResolverMap.combine(router.getConfiguration().getBaseLocation(), location)); } private OpenAPI parseFileAsOpenAPI(File oaFile) { @@ -201,7 +201,7 @@ private void addConversionNoticeIfSwagger2(OpenAPI api, JsonNode node) { } private String resolve(String filepath) { - return ResolverMap.combine(router.getBaseLocation(), filepath); + return ResolverMap.combine(router.getConfiguration().getBaseLocation(), filepath); } private static @NotNull ParseOptions getParseOptions() { diff --git a/core/src/main/java/com/predic8/membrane/core/proxies/AbstractServiceProxy.java b/core/src/main/java/com/predic8/membrane/core/proxies/AbstractServiceProxy.java index fb8086dfc6..503d3be7e1 100644 --- a/core/src/main/java/com/predic8/membrane/core/proxies/AbstractServiceProxy.java +++ b/core/src/main/java/com/predic8/membrane/core/proxies/AbstractServiceProxy.java @@ -35,7 +35,7 @@ public void init() { if (target.getPort() == -1) target.setPort(target.getSslParser() != null ? 443 : 80); if (target.getSslParser() != null) - setSslOutboundContext(new StaticSSLContext(target.getSslParser(), router.getResolverMap(), router.getBaseLocation())); + setSslOutboundContext(new StaticSSLContext(target.getSslParser(), router.getResolverMap(), router.getConfiguration().getBaseLocation())); target.init(router); } diff --git a/core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java b/core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java index 3f7e2b779e..581b8bd2e6 100644 --- a/core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java +++ b/core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java @@ -178,7 +178,7 @@ private void configureRewritingOfPath(String targetPath) { private @NotNull WSDLParserContext getWsdlParserContext() { WSDLParserContext ctx = new WSDLParserContext(); - ctx.setInput(ResolverMap.combine(router.getBaseLocation(), wsdl)); + ctx.setInput(ResolverMap.combine(router.getConfiguration().getBaseLocation(), wsdl)); return ctx; } diff --git a/core/src/main/java/com/predic8/membrane/core/proxies/SSLProxy.java b/core/src/main/java/com/predic8/membrane/core/proxies/SSLProxy.java index 3442923a13..0d60b3bc0d 100644 --- a/core/src/main/java/com/predic8/membrane/core/proxies/SSLProxy.java +++ b/core/src/main/java/com/predic8/membrane/core/proxies/SSLProxy.java @@ -329,7 +329,7 @@ private SSLParser getSSLParser() { private class ForwardingStaticSSLContext extends StaticSSLContext { public ForwardingStaticSSLContext() { - super(getSSLParser(), SSLProxy.this.router.getResolverMap(), SSLProxy.this.router.getBaseLocation()); + super(getSSLParser(), SSLProxy.this.router.getResolverMap(), SSLProxy.this.router.getConfiguration().getBaseLocation()); } @Override diff --git a/core/src/main/java/com/predic8/membrane/core/proxies/SSLableProxy.java b/core/src/main/java/com/predic8/membrane/core/proxies/SSLableProxy.java index 6974b00e30..dcc27d4692 100644 --- a/core/src/main/java/com/predic8/membrane/core/proxies/SSLableProxy.java +++ b/core/src/main/java/com/predic8/membrane/core/proxies/SSLableProxy.java @@ -127,8 +127,8 @@ public boolean isInboundSSL() { private @NotNull SSLContext generateSslInboundContext() { if (sslInboundParser.getKeyGenerator() != null) - return new GeneratingSSLContext(sslInboundParser, router.getResolverMap(), router.getBaseLocation()); - return new StaticSSLContext(sslInboundParser, router.getResolverMap(), router.getBaseLocation()); + return new GeneratingSSLContext(sslInboundParser, router.getResolverMap(), router.getConfiguration().getBaseLocation()); + return new StaticSSLContext(sslInboundParser, router.getResolverMap(), router.getConfiguration().getBaseLocation()); } } diff --git a/core/src/main/java/com/predic8/membrane/core/router/Configuration.java b/core/src/main/java/com/predic8/membrane/core/router/Configuration.java index 712beb7c03..551d780cd4 100644 --- a/core/src/main/java/com/predic8/membrane/core/router/Configuration.java +++ b/core/src/main/java/com/predic8/membrane/core/router/Configuration.java @@ -14,13 +14,14 @@ package com.predic8.membrane.core.router; -import com.predic8.membrane.annot.MCAttribute; -import com.predic8.membrane.annot.MCChildElement; -import com.predic8.membrane.annot.MCElement; -import com.predic8.membrane.core.interceptor.administration.AdminConsoleInterceptor; -import com.predic8.membrane.core.proxies.Proxy; -import com.predic8.membrane.core.util.URIFactory; - +import com.predic8.membrane.annot.*; +import com.predic8.membrane.core.interceptor.administration.*; +import com.predic8.membrane.core.proxies.*; +import com.predic8.membrane.core.util.*; + +/** + * Global Membrane configuration. + */ @MCElement(name = "configuration", topLevel = true, component = false) public class Configuration { @@ -41,6 +42,8 @@ public class Configuration { private URIFactory uriFactory = new URIFactory(false); + private String baseLocation; + /** * @param hotDeploy If true the hot deploy feature will be activated during init of the Router. * @description

Whether changes to the router's configuration file should automatically trigger a restart. @@ -75,7 +78,7 @@ public int getRetryInitInterval() { } /** - * @description

Whether the router should continue startup, if initialization of a rule (proxy, serviceProxy or soapProxy) failed + * @description

Whether the router should continue startup, if initialization of a rule (proxy, serviceProxy or soapProxy) failed * (for example, when a WSDL a component depends on could not be downloaded).

*

If false, the router will exit with code -1 just after startup, when the initialization of a rule failed.

*

If true, the router will continue startup, and all rules which could not be initialized will be inactive (=not @@ -113,7 +116,7 @@ public String getJmx() { } /** - * @description

By default the error messages Membrane sends back to an HTTP client provide information to help the caller + * @description

By default the error messages Membrane sends back to an HTTP client provide information to help the caller * find the problem. The caller might even get sensitive information. In production the error messages should not reveal * to much details. With this option you can put Membrane in production mode and reduce the amount of information in * error messages.

@@ -140,4 +143,17 @@ public void setUriFactory(URIFactory uriFactory) { public URIFactory getUriFactory() { return uriFactory; } + + /** + * @description Base location for the router's configuration file. + * @param baseLocation + */ + @MCAttribute() + public void setBaseLocation(String baseLocation) { + this.baseLocation = baseLocation; + } + + public String getBaseLocation() { + return baseLocation; + } } diff --git a/core/src/main/java/com/predic8/membrane/core/router/DefaultMainComponents.java b/core/src/main/java/com/predic8/membrane/core/router/DefaultMainComponents.java index 38038a9d8b..995f5cc78d 100644 --- a/core/src/main/java/com/predic8/membrane/core/router/DefaultMainComponents.java +++ b/core/src/main/java/com/predic8/membrane/core/router/DefaultMainComponents.java @@ -108,7 +108,7 @@ public RuleManager getRuleManager() { public void setApplicationContext(ApplicationContext ctx) throws BeansException { beanFactory = ctx; if (ctx instanceof BaseLocationApplicationContext blac) - router.setBaseLocation(blac.getBaseLocation()); + router.getConfiguration().setBaseLocation(blac.getBaseLocation()); } public void setRuleManager(RuleManager ruleManager) { diff --git a/core/src/main/java/com/predic8/membrane/core/router/DefaultRouter.java b/core/src/main/java/com/predic8/membrane/core/router/DefaultRouter.java index cb60c1754c..9d1fcca232 100644 --- a/core/src/main/java/com/predic8/membrane/core/router/DefaultRouter.java +++ b/core/src/main/java/com/predic8/membrane/core/router/DefaultRouter.java @@ -50,35 +50,19 @@ import static com.predic8.membrane.core.util.DLPUtil.*; /* - Responsibilities: - - Start and stop Membrane - - Start, stop internal services - - Control lifecycle of proxies - - TODO: - - ADR: First start router than init and add proxies or first init proxies and add them later? - - ADR: - - The Router is responsible for the lifecycle of the proxies - - Ports are opened in start() - - init() - - does not open ports - - inits the proxies - - In sequence as added or reverse or not defined? - - new Router(), add(proxy) init() start() - - add(proxy) could be called any time - - If router is started port will be opened if needed by the proxy - - What if a proxy needs to make a call to another proxy during init(Tests: e.g. B2C) - - Delete addProxyAndOpenPortIfNew() from RuleManager - - HTTPRouter: - - Purpose? Test? - - - JMX - - Beans added after Router.start() should also be exported as JMS beans - + * Responsibilities: + * - Start and stop Membrane, proxies and internal services + * - Control the lifecycle of proxies + * + * + * TODO: + * - ADR: First start router than init and add proxies or first init proxies and add them later? + * - JMX + * - Beans added after Router.start() should also be exported as JMS beans + * + * Questions: + * - What if a proxy needs to make a call to another proxy during init(Tests: e.g. B2C) */ - /** * @description

* Membrane API Gateway's main object. @@ -108,11 +92,7 @@ public class DefaultRouter extends AbstractRouter implements ApplicationContextA protected DefaultMainComponents mainComponents; - // - // Configuration - // private String id; - private String baseLocation; private Configuration configuration = new Configuration(); @@ -125,7 +105,7 @@ public class DefaultRouter extends AbstractRouter implements ApplicationContextA private boolean initialized; /** - * HotDeployer for changes on the XML configuration file. Does not cover YAML. + * HotDeployer for changes on the configuration file. * Not synchronized, since only modified during initialization */ private HotDeployer hotDeployer = new DefaultHotDeployer(); @@ -140,12 +120,11 @@ public DefaultRouter() { /** * Initializes the {@code Router} * - by setting up its associated components. - * - calling init() on each of its {@link Proxy} instances. - *

+ * - calling init() on each of its {@link Proxy} instances + * * This method ensures that the {@code Router} and its dependencies are prepared for operation. * But it does not start the router itself. Use {@link #start()} to start the router. * If start() is called a separate call to init() is not needed. - * The init() is useful for testing without the expensive start() call. */ public void init() { log.debug("Initializing."); @@ -183,14 +162,10 @@ public void start() { } try { - getRegistry().getBean(KubernetesWatcher.class).ifPresent(KubernetesWatcher::start); - startJmx(); getRuleManager().openPorts(); - hotDeployer.start(this); - if (configuration.getRetryInitInterval() > 0) reinitializer.start(); } catch (DuplicatePathException e) { @@ -288,10 +263,10 @@ public ResolverMap getResolverMap() { } /** - * Adds a proxy to the router and initializes it. + * Adds a proxy to the router. * Can be called at any time before or after start(). * - * TODO: Should we sync running cause a different Thread might call add? + * If called after start(), the port will be opened automatically. * * @param proxy * @throws IOException @@ -317,7 +292,6 @@ private void startJmx() { log.debug("Starting JMX."); try { JmxExporter exporter = mainComponents.getBeanFactory().getBean(JMX_EXPORTER_NAME, JmxExporter.class); - //exporter.removeBean(prefix + jmxRouterName); exporter.addBean("io.membrane-api:00=routers, name=" + configuration.getJmx(), new JmxRouter(this, exporter)); exporter.initAfterBeansAdded(); } catch (NoSuchBeanDefinitionException ignored) { @@ -347,22 +321,10 @@ public boolean isRunning() { } } - public String getBaseLocation() { - return baseLocation; - } - - public void setBaseLocation(String baseLocation) { - this.baseLocation = baseLocation; - } - public ApplicationContext getBeanFactory() { return mainComponents.getBeanFactory(); } - public boolean isProduction() { - return configuration.isProduction(); - } - public Statistics getStatistics() { return mainComponents.getStatistics(); } @@ -463,7 +425,6 @@ public void setRegistry(BeanRegistry registry) { mainComponents.setRegistry(registry); } - public BeanRegistry getRegistry() { return mainComponents.getRegistry(); } diff --git a/core/src/main/java/com/predic8/membrane/core/router/Router.java b/core/src/main/java/com/predic8/membrane/core/router/Router.java index da3d7bc599..f7ad964e1c 100644 --- a/core/src/main/java/com/predic8/membrane/core/router/Router.java +++ b/core/src/main/java/com/predic8/membrane/core/router/Router.java @@ -27,6 +27,4 @@ public interface Router extends Lifecycle, MainComponents { Configuration getConfiguration(); - String getBaseLocation(); - } diff --git a/core/src/main/java/com/predic8/membrane/core/sslinterceptor/RouterIpResolverInterceptor.java b/core/src/main/java/com/predic8/membrane/core/sslinterceptor/RouterIpResolverInterceptor.java index 097d31c2d4..519869eac3 100644 --- a/core/src/main/java/com/predic8/membrane/core/sslinterceptor/RouterIpResolverInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/sslinterceptor/RouterIpResolverInterceptor.java @@ -115,7 +115,7 @@ public void setSslParser(SSLParser sslParser) { public void init(Router router) { httpClient = router.getHttpClientFactory().createClient(httpClientConfiguration); if (sslParser != null) - sslContext = new StaticSSLContext(sslParser, router.getResolverMap(), router.getBaseLocation()); + sslContext = new StaticSSLContext(sslParser, router.getResolverMap(), router.getConfiguration().getBaseLocation()); } @Override diff --git a/core/src/test/java/com/predic8/membrane/core/interceptor/jwt/JwtAuthInterceptorTest.java b/core/src/test/java/com/predic8/membrane/core/interceptor/jwt/JwtAuthInterceptorTest.java index b036241f5e..9b444f5b6b 100644 --- a/core/src/test/java/com/predic8/membrane/core/interceptor/jwt/JwtAuthInterceptorTest.java +++ b/core/src/test/java/com/predic8/membrane/core/interceptor/jwt/JwtAuthInterceptorTest.java @@ -13,31 +13,25 @@ package com.predic8.membrane.core.interceptor.jwt; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.predic8.membrane.core.exchange.Exchange; -import com.predic8.membrane.core.http.Request; -import com.predic8.membrane.core.resolver.ResolverMap; +import com.fasterxml.jackson.core.type.*; +import com.fasterxml.jackson.databind.*; +import com.predic8.membrane.core.exchange.*; +import com.predic8.membrane.core.http.*; import com.predic8.membrane.core.router.*; -import com.predic8.membrane.core.util.functionalInterfaces.ExceptionThrowingConsumer; -import org.jose4j.jwk.RsaJsonWebKey; -import org.jose4j.jwk.RsaJwkGenerator; -import org.jose4j.jws.AlgorithmIdentifiers; -import org.jose4j.jws.JsonWebSignature; -import org.jose4j.jwt.JwtClaims; -import org.jose4j.lang.JoseException; -import org.junit.jupiter.api.Named; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Map; -import java.util.stream.Stream; +import com.predic8.membrane.core.util.functionalInterfaces.*; +import org.jose4j.jwk.*; +import org.jose4j.jws.*; +import org.jose4j.jwt.*; +import org.jose4j.lang.*; +import org.junit.jupiter.api.*; +import org.junit.jupiter.params.*; +import org.junit.jupiter.params.provider.*; + +import java.io.*; +import java.util.*; +import java.util.stream.*; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; public class JwtAuthInterceptorTest{ @@ -260,12 +254,8 @@ private JwtAuthInterceptor prepareInterceptor(RsaJsonWebKey publicOnly) throws E return initInterceptor(createInterceptor(publicOnly)); } - private JwtAuthInterceptor initInterceptor(JwtAuthInterceptor interceptor) throws Exception { - DefaultRouter mock = mock(DefaultRouter.class); - when(mock.getBaseLocation()).thenReturn(""); - when(mock.getResolverMap()).thenReturn(new ResolverMap()); - when(mock.getConfiguration()).thenReturn(new Configuration()); - interceptor.init(mock); + private JwtAuthInterceptor initInterceptor(JwtAuthInterceptor interceptor) { + interceptor.init(new DummyTestRouter()); return interceptor; } @@ -289,13 +279,10 @@ private static String getSignedJwt(RsaJsonWebKey privateKey) throws JoseExceptio private static String getSignedJwt(RsaJsonWebKey privateKey, JwtClaims claims) throws JoseException { JsonWebSignature jws = new JsonWebSignature(); - jws.setPayload(claims.toJson()); - jws.setKey(privateKey.getPrivateKey()); jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); jws.setKeyIdHeaderValue(privateKey.getKeyId()); - return jws.getCompactSerialization(); } @@ -307,7 +294,6 @@ private static JwtClaims createClaims(String audience, String tenantId){ claims.setSubject(SUB_CLAIM_CONTENT); claims.setAudience(audience); claims.setClaim("tid", tenantId); - return claims; } diff --git a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptorTest.java b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptorTest.java index 80ee656af6..0bd8c20331 100644 --- a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptorTest.java +++ b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptorTest.java @@ -53,7 +53,7 @@ public class OpenAPIPublisherInterceptorTest { void setUp() { DefaultRouter router = new DefaultRouter(); router.getConfiguration().setUriFactory(new URIFactory()); - router.setBaseLocation(""); + router.getConfiguration().setBaseLocation(""); openAPIRecordFactory = new OpenAPIRecordFactory(router); OpenAPISpec spec = new OpenAPISpec(); spec.setDir("src/test/resources/openapi/specs"); diff --git a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordFactoryTest.java b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordFactoryTest.java index 76dbca1819..c1de2b4abc 100644 --- a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordFactoryTest.java +++ b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordFactoryTest.java @@ -31,7 +31,7 @@ class OpenAPIRecordFactoryTest { @BeforeAll static void setUp() { DummyTestRouter router = new DummyTestRouter(); - router.setBaseLocation("src/test/resources/openapi/specs/"); + router.getConfiguration().setBaseLocation("src/test/resources/openapi/specs/"); factory = new OpenAPIRecordFactory(router); } diff --git a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordTest.java b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordTest.java index 78395a1785..0f86a1e683 100644 --- a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordTest.java +++ b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordTest.java @@ -31,7 +31,7 @@ class OpenAPIRecordTest { void setUp() { DefaultRouter router = new DefaultRouter(); router.getConfiguration().setUriFactory(new URIFactory()); - router.setBaseLocation(""); + router.getConfiguration().setBaseLocation(""); get.setRequest(new Request.Builder().method("GET").build()); get.setProxy(new NullProxy()); diff --git a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/RewriteTest.java b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/RewriteTest.java index 641cfe7375..e7ab9462c2 100644 --- a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/RewriteTest.java +++ b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/RewriteTest.java @@ -51,7 +51,7 @@ void setUp() { DefaultRouter router = new DefaultRouter(); router.getConfiguration().setUriFactory(new URIFactory()); - router.setBaseLocation(""); + router.getConfiguration().setBaseLocation(""); OpenAPIRecordFactory openAPIRecordFactory = new OpenAPIRecordFactory(router); diff --git a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/XMembraneExtensionSecurityTest.java b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/XMembraneExtensionSecurityTest.java index 9642537558..9d784d3b99 100644 --- a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/XMembraneExtensionSecurityTest.java +++ b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/XMembraneExtensionSecurityTest.java @@ -33,7 +33,7 @@ public class XMembraneExtensionSecurityTest { @BeforeEach void setUp() { DummyTestRouter router = new DummyTestRouter(); - router.setBaseLocation(""); + router.getConfiguration().setBaseLocation(""); OpenAPIRecordFactory factory = new OpenAPIRecordFactory(router); OpenAPISpec spec = new OpenAPISpec(); spec.setLocation(getPathFromResource("openapi/openapi-proxy/validate-security-extensions.yml")); diff --git a/core/src/test/java/com/predic8/membrane/core/router/DummyTestRouter.java b/core/src/test/java/com/predic8/membrane/core/router/DummyTestRouter.java index 93875051a6..8301b17853 100644 --- a/core/src/test/java/com/predic8/membrane/core/router/DummyTestRouter.java +++ b/core/src/test/java/com/predic8/membrane/core/router/DummyTestRouter.java @@ -52,8 +52,6 @@ public class DummyTestRouter extends AbstractRouter { private final Statistics statistics = new Statistics(); private ApplicationContext applicationContext; - private String baseLocation; - private Configuration configuration = new Configuration(); public DummyTestRouter() { @@ -107,11 +105,6 @@ public RuleManager getRuleManager() { return ruleManager; } - @Override - public String getBaseLocation() { - return baseLocation; - } - @Override public ResolverMap getResolverMap() { return resolverMap; @@ -191,8 +184,4 @@ public HttpClientConfiguration getHttpClientConfig() { public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } - - public void setBaseLocation(String baseLocation) { - this.baseLocation = baseLocation; - } } diff --git a/core/src/test/java/com/predic8/membrane/core/router/TestRouter.java b/core/src/test/java/com/predic8/membrane/core/router/TestRouter.java index 4f101f4171..87f25fb9c1 100644 --- a/core/src/test/java/com/predic8/membrane/core/router/TestRouter.java +++ b/core/src/test/java/com/predic8/membrane/core/router/TestRouter.java @@ -175,11 +175,6 @@ public Configuration getConfiguration() { return configuration; } - @Override - public String getBaseLocation() { - return ""; - } - @Override public void stop() { transport.closeAll(); diff --git a/core/src/test/java/com/predic8/membrane/core/security/JWTSecuritySchemeTest.java b/core/src/test/java/com/predic8/membrane/core/security/JWTSecuritySchemeTest.java index 9538292c99..5e9b98b1a1 100644 --- a/core/src/test/java/com/predic8/membrane/core/security/JWTSecuritySchemeTest.java +++ b/core/src/test/java/com/predic8/membrane/core/security/JWTSecuritySchemeTest.java @@ -15,7 +15,6 @@ import com.predic8.membrane.core.exchange.*; import com.predic8.membrane.core.interceptor.jwt.*; -import com.predic8.membrane.core.resolver.*; import com.predic8.membrane.core.router.*; import org.jose4j.jwk.*; import org.jose4j.jws.*; @@ -25,9 +24,7 @@ import java.util.*; -import static com.predic8.membrane.core.http.Request.get; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static com.predic8.membrane.core.http.Request.*; class JWTSecuritySchemeTest { @@ -54,11 +51,7 @@ private JwtAuthInterceptor prepareInterceptor(RsaJsonWebKey publicOnly) throws E } private JwtAuthInterceptor initInterceptor(JwtAuthInterceptor interceptor) throws Exception { - DefaultRouter mock = mock(DefaultRouter.class); - when(mock.getBaseLocation()).thenReturn(""); - when(mock.getResolverMap()).thenReturn(new ResolverMap()); - when(mock.getConfiguration()).thenReturn(new Configuration()); - interceptor.init(mock); + interceptor.init(new DummyTestRouter()); return interceptor; } @@ -93,13 +86,10 @@ private static JwtClaims createClaims(String audience){ private static String getSignedJwt(RsaJsonWebKey privateKey, JwtClaims claims) throws JoseException { JsonWebSignature jws = new JsonWebSignature(); - jws.setPayload(claims.toJson()); - jws.setKey(privateKey.getPrivateKey()); jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); jws.setKeyIdHeaderValue("membrane"); - return jws.getCompactSerialization(); } diff --git a/core/src/test/java/com/predic8/membrane/core/security/KeyStoreUtilTest.java b/core/src/test/java/com/predic8/membrane/core/security/KeyStoreUtilTest.java index da32593149..8a34c01372 100644 --- a/core/src/test/java/com/predic8/membrane/core/security/KeyStoreUtilTest.java +++ b/core/src/test/java/com/predic8/membrane/core/security/KeyStoreUtilTest.java @@ -48,7 +48,7 @@ static void setUp() throws Exception { sslParser.setKeyStore(new KeyStore()); sslParser.getKeyStore().setLocation("classpath:/alias-keystore.p12"); sslParser.getKeyStore().setKeyPassword(KEYSTORE_PASSWORD); - keyStore = getAndLoadKeyStore(sslParser.getKeyStore(), router.getResolverMap(), router.getBaseLocation(), "PKCS12", KEYSTORE_PASSWORD.toCharArray()); + keyStore = getAndLoadKeyStore(sslParser.getKeyStore(), router.getResolverMap(), router.getConfiguration().getBaseLocation(), "PKCS12", KEYSTORE_PASSWORD.toCharArray()); } @AfterAll @@ -61,7 +61,7 @@ void testFilterKeyStoreByAlias() throws KeyStoreException, NoSuchProviderExcepti KeyStore store = new KeyStore(); store.setLocation("classpath:/alias-keystore.p12"); store.setKeyPassword(KEYSTORE_PASSWORD); - java.security.KeyStore loadedKeyStore = getAndLoadKeyStore(store, router.getResolverMap(), router.getBaseLocation(), "PKCS12", KEYSTORE_PASSWORD.toCharArray()); + java.security.KeyStore loadedKeyStore = getAndLoadKeyStore(store, router.getResolverMap(), router.getConfiguration().getBaseLocation(), "PKCS12", KEYSTORE_PASSWORD.toCharArray()); assertNotNull(loadedKeyStore); assertEquals(2, loadedKeyStore.size()); java.security.KeyStore filteredKeyStore = filterKeyStoreByAlias(loadedKeyStore, "secret".toCharArray(), "key1"); @@ -79,7 +79,7 @@ void testGetAndLoadKeyStore() throws KeyStoreException, NoSuchProviderException, KeyStore store = new KeyStore(); store.setLocation("classpath:/alias-keystore.p12"); store.setKeyPassword(KEYSTORE_PASSWORD); - java.security.KeyStore loadedKeyStore = getAndLoadKeyStore(store, router.getResolverMap(), router.getBaseLocation(), "PKCS12", KEYSTORE_PASSWORD.toCharArray()); + java.security.KeyStore loadedKeyStore = getAndLoadKeyStore(store, router.getResolverMap(), router.getConfiguration().getBaseLocation(), "PKCS12", KEYSTORE_PASSWORD.toCharArray()); assertNotNull(loadedKeyStore); assertTrue(loadedKeyStore.size() > 0); assertTrue(loadedKeyStore.containsAlias(ALIAS)); diff --git a/core/src/test/java/com/predic8/membrane/core/transport/ssl/SSLContextTest.java b/core/src/test/java/com/predic8/membrane/core/transport/ssl/SSLContextTest.java index 25371e76a7..e7f3e89695 100644 --- a/core/src/test/java/com/predic8/membrane/core/transport/ssl/SSLContextTest.java +++ b/core/src/test/java/com/predic8/membrane/core/transport/ssl/SSLContextTest.java @@ -60,7 +60,7 @@ public SSLContextBuilder() { } public StaticSSLContext build() { - return new StaticSSLContext(sslParser, router.getResolverMap(), router.getBaseLocation()); + return new StaticSSLContext(sslParser, router.getResolverMap(), router.getConfiguration().getBaseLocation()); } private SSLContextBuilder byKeyAlias(String alias) { diff --git a/core/src/test/java/com/predic8/membrane/core/transport/ssl/acme/AcmeStepTest.java b/core/src/test/java/com/predic8/membrane/core/transport/ssl/acme/AcmeStepTest.java index 42618cfe40..b40f46f284 100644 --- a/core/src/test/java/com/predic8/membrane/core/transport/ssl/acme/AcmeStepTest.java +++ b/core/src/test/java/com/predic8/membrane/core/transport/ssl/acme/AcmeStepTest.java @@ -150,7 +150,7 @@ public Outcome handleRequest(Exchange exc) { certificate.setContent(sim.getCA().getCertificate()); trust.setCertificateList(ImmutableList.of(certificate)); sslParser1.setTrust(trust); - e.setProperty(Exchange.SSL_CONTEXT, new StaticSSLContext(sslParser1, router.getResolverMap(), router.getBaseLocation())); + e.setProperty(Exchange.SSL_CONTEXT, new StaticSSLContext(sslParser1, router.getResolverMap(), router.getConfiguration().getBaseLocation())); hc.call(e); assertEquals(234, e.getResponse().getStatusCode()); } diff --git a/core/src/test/java/com/predic8/membrane/integration/withoutinternet/interceptor/AcmeRenewTest.java b/core/src/test/java/com/predic8/membrane/integration/withoutinternet/interceptor/AcmeRenewTest.java index e04659dd0e..b091bb63a6 100644 --- a/core/src/test/java/com/predic8/membrane/integration/withoutinternet/interceptor/AcmeRenewTest.java +++ b/core/src/test/java/com/predic8/membrane/integration/withoutinternet/interceptor/AcmeRenewTest.java @@ -106,7 +106,7 @@ public Outcome handleRequest(Exchange exc) { certificate.setContent(sim.getCA().getCertificate()); trust.setCertificateList(ImmutableList.of(certificate)); sslParser1.setTrust(trust); - e.setProperty(SSL_CONTEXT, new StaticSSLContext(sslParser1, router.getResolverMap(), router.getBaseLocation())); + e.setProperty(SSL_CONTEXT, new StaticSSLContext(sslParser1, router.getResolverMap(), router.getConfiguration().getBaseLocation())); hc.call(e); } From f98b2e995f92ede460e1a7b1aa973862a2ae5387 Mon Sep 17 00:00:00 2001 From: Thomas Bayer Date: Fri, 2 Jan 2026 18:28:55 +0100 Subject: [PATCH 2/5] refactor: improve JMX lifecycle management and HotDeployer YAML support - Replace `DefaultRouter` with `Router` in `JmxRouter` for enhanced abstraction. - Introduce `JMX_NAMESPACE` for improved consistency in bean names. - Enhance `JmxExporter` with static factory methods and improved `Router` integration. - Update `HotDeployer` to provide debug logging for unsupported YAML configurations. --- .../membrane/core/jmx/JmxExporter.java | 95 +++++++++++-------- .../predic8/membrane/core/jmx/JmxRouter.java | 6 +- .../membrane/core/router/Configuration.java | 2 +- .../membrane/core/router/DefaultRouter.java | 26 ++--- .../membrane/core/router/MainComponents.java | 3 + .../router/hotdeploy/DefaultHotDeployer.java | 19 ++-- 6 files changed, 86 insertions(+), 65 deletions(-) diff --git a/core/src/main/java/com/predic8/membrane/core/jmx/JmxExporter.java b/core/src/main/java/com/predic8/membrane/core/jmx/JmxExporter.java index 3d536276ec..ffc70223ab 100644 --- a/core/src/main/java/com/predic8/membrane/core/jmx/JmxExporter.java +++ b/core/src/main/java/com/predic8/membrane/core/jmx/JmxExporter.java @@ -13,39 +13,35 @@ package com.predic8.membrane.core.jmx; -import com.predic8.membrane.annot.MCElement; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.Lifecycle; -import org.springframework.jmx.export.MBeanExporter; -import org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource; -import org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler; -import org.springframework.jmx.support.RegistrationPolicy; - -import java.util.HashMap; - -@MCElement(name=JmxExporter.JMX_EXPORTER_NAME) -public class JmxExporter extends MBeanExporter implements Lifecycle, ApplicationContextAware, DisposableBean { +import com.predic8.membrane.annot.*; +import com.predic8.membrane.core.router.*; +import org.slf4j.*; +import org.springframework.beans.factory.*; +import org.springframework.context.*; +import org.springframework.jmx.export.*; +import org.springframework.jmx.export.annotation.*; +import org.springframework.jmx.export.assembler.*; - public static final String JMX_EXPORTER_NAME = "jmxExporter"; - final HashMap jmxBeans = new HashMap<>(); +import java.util.*; - ApplicationContext context; +import static org.springframework.jmx.support.RegistrationPolicy.*; - MBeanExporter exporter; +@MCElement(name = JmxExporter.JMX_EXPORTER_NAME) +public class JmxExporter extends MBeanExporter implements Lifecycle { + private static final Logger log = LoggerFactory.getLogger(MBeanExporter.class); - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.context = applicationContext; - } + public static final String JMX_EXPORTER_NAME = "jmxExporter"; + public static final String JMX_NAMESPACE = "io.membrane-api"; + + private final HashMap jmxBeans = new HashMap<>(); + + private MBeanExporter exporter; @Override public void start() { exporter = new MBeanExporter(); - exporter.setRegistrationPolicy(RegistrationPolicy.IGNORE_EXISTING); + exporter.setRegistrationPolicy(IGNORE_EXISTING); MetadataMBeanInfoAssembler assembler = new MetadataMBeanInfoAssembler(); assembler.setAttributeSource(new AnnotationJmxAttributeSource()); assembler.afterPropertiesSet(); @@ -54,7 +50,8 @@ public void start() { @Override public void stop() { - + jmxBeans.clear(); + exporter.destroy(); } @Override @@ -62,23 +59,47 @@ public boolean isRunning() { return false; } - @Override - public void destroy() { - jmxBeans.clear(); - exporter.destroy(); + public void addBean(String fullyQualifiedMBeanName, Object bean) { + jmxBeans.put(fullyQualifiedMBeanName, bean); } - public void addBean(String fullyQualifiedMBeanName, Object bean ) { - jmxBeans.put(fullyQualifiedMBeanName,bean); - } - - public void removeBean(String fullyQualifiedMBeanName){ - jmxBeans.remove(fullyQualifiedMBeanName); - } + public void initAfterBeansAdded() { + // Temporary workaround till YAML start calls start() on components + if (exporter == null) + start(); - public void initAfterBeansAdded(){ exporter.setBeans(jmxBeans); exporter.afterPropertiesSet(); exporter.afterSingletonsInstantiated(); } + + public void addRouter(Router router) { + try { + addBean(JMX_NAMESPACE + ":00=routers, name=" + router.getConfiguration().getJmx(), new JmxRouter(router, this)); + initAfterBeansAdded(); + } catch (NoSuchBeanDefinitionException ignored) { + // If bean is not available do not init jmx + } + } + + + public static void start(Router router) { + var eo = getExporter(router); + if (eo.isEmpty()) { + log.debug("Not starting JMX exporter. Declare component in YAML or element in XML"); + return; + } + log.debug("Starting JMX."); + eo.get().addRouter(router); + } + + public static Optional getExporter(Router router) { + var exporter = router.getRegistry().getBean(JmxExporter.class); + if (exporter.isPresent()) return exporter; + if (router.getBeanFactory() == null) { + return Optional.empty(); + } + return Optional.of(router.getBeanFactory().getBean(JMX_EXPORTER_NAME, JmxExporter.class)); + } + } diff --git a/core/src/main/java/com/predic8/membrane/core/jmx/JmxRouter.java b/core/src/main/java/com/predic8/membrane/core/jmx/JmxRouter.java index c81fc98f7d..051e9344fe 100644 --- a/core/src/main/java/com/predic8/membrane/core/jmx/JmxRouter.java +++ b/core/src/main/java/com/predic8/membrane/core/jmx/JmxRouter.java @@ -17,6 +17,8 @@ import com.predic8.membrane.core.router.*; import org.springframework.jmx.export.annotation.*; +import static com.predic8.membrane.core.jmx.JmxExporter.JMX_NAMESPACE; + @ManagedResource() public class JmxRouter { @@ -24,7 +26,7 @@ public class JmxRouter { private final Router router; private final JmxExporter exporter; - public JmxRouter(DefaultRouter router, JmxExporter exporter) { + public JmxRouter(Router router, JmxExporter exporter) { this.router = router; this.exporter = exporter; exportServiceProxyList(); @@ -44,7 +46,7 @@ private void exportServiceProxyList(){ } private void exportServiceProxy(ServiceProxy rule) { - String prefix = "org.membrane-soa:00=serviceProxies, 01=%s, name=".formatted(router.getConfiguration().getJmx()); + String prefix = JMX_NAMESPACE + ":00=apis, 01=%s, name=".formatted(router.getConfiguration().getJmx()); exporter.addBean(prefix + rule.getName().replace(":",""), new JmxServiceProxy(rule, router)); } } diff --git a/core/src/main/java/com/predic8/membrane/core/router/Configuration.java b/core/src/main/java/com/predic8/membrane/core/router/Configuration.java index 551d780cd4..2e2f9659ab 100644 --- a/core/src/main/java/com/predic8/membrane/core/router/Configuration.java +++ b/core/src/main/java/com/predic8/membrane/core/router/Configuration.java @@ -146,7 +146,7 @@ public URIFactory getUriFactory() { /** * @description Base location for the router's configuration file. - * @param baseLocation + * @param baseLocation The base directory path used to resolve relative file paths in configuration */ @MCAttribute() public void setBaseLocation(String baseLocation) { diff --git a/core/src/main/java/com/predic8/membrane/core/router/DefaultRouter.java b/core/src/main/java/com/predic8/membrane/core/router/DefaultRouter.java index 9d1fcca232..8f847e4ce6 100644 --- a/core/src/main/java/com/predic8/membrane/core/router/DefaultRouter.java +++ b/core/src/main/java/com/predic8/membrane/core/router/DefaultRouter.java @@ -54,12 +54,6 @@ * - Start and stop Membrane, proxies and internal services * - Control the lifecycle of proxies * - * - * TODO: - * - ADR: First start router than init and add proxies or first init proxies and add them later? - * - JMX - * - Beans added after Router.start() should also be exported as JMS beans - * * Questions: * - What if a proxy needs to make a call to another proxy during init(Tests: e.g. B2C) */ @@ -163,7 +157,7 @@ public void start() { try { getRegistry().getBean(KubernetesWatcher.class).ifPresent(KubernetesWatcher::start); - startJmx(); + JmxExporter.start(this); getRuleManager().openPorts(); hotDeployer.start(this); if (configuration.getRetryInitInterval() > 0) @@ -284,21 +278,16 @@ public void add(Proxy proxy) throws IOException { } - private void startJmx() { + private Optional getExporter() { + var exporter= mainComponents.getRegistry().getBean(JmxExporter.class); + if (exporter.isPresent()) return exporter; if (mainComponents.getBeanFactory() == null) { - log.info("No bean factory available, not starting JMX."); - return; - } - log.debug("Starting JMX."); - try { - JmxExporter exporter = mainComponents.getBeanFactory().getBean(JMX_EXPORTER_NAME, JmxExporter.class); - exporter.addBean("io.membrane-api:00=routers, name=" + configuration.getJmx(), new JmxRouter(this, exporter)); - exporter.initAfterBeansAdded(); - } catch (NoSuchBeanDefinitionException ignored) { - // If bean is not available do not init jmx + return Optional.empty(); } + return Optional.of(mainComponents.getBeanFactory().getBean(JMX_EXPORTER_NAME, JmxExporter.class)); } + @Override public void stop() { getRegistry().getBean(KubernetesWatcher.class).ifPresent(KubernetesWatcher::stop); @@ -425,6 +414,7 @@ public void setRegistry(BeanRegistry registry) { mainComponents.setRegistry(registry); } + @Override public BeanRegistry getRegistry() { return mainComponents.getRegistry(); } diff --git a/core/src/main/java/com/predic8/membrane/core/router/MainComponents.java b/core/src/main/java/com/predic8/membrane/core/router/MainComponents.java index 112bc054be..65b08f3c61 100644 --- a/core/src/main/java/com/predic8/membrane/core/router/MainComponents.java +++ b/core/src/main/java/com/predic8/membrane/core/router/MainComponents.java @@ -14,6 +14,7 @@ package com.predic8.membrane.core.router; +import com.predic8.membrane.annot.beanregistry.*; import com.predic8.membrane.core.exchangestore.*; import com.predic8.membrane.core.interceptor.*; import com.predic8.membrane.core.kubernetes.client.*; @@ -31,6 +32,8 @@ */ public interface MainComponents { + BeanRegistry getRegistry(); + Transport getTransport(); FlowController getFlowController(); diff --git a/core/src/main/java/com/predic8/membrane/core/router/hotdeploy/DefaultHotDeployer.java b/core/src/main/java/com/predic8/membrane/core/router/hotdeploy/DefaultHotDeployer.java index 7a007dbc90..591214c5ee 100644 --- a/core/src/main/java/com/predic8/membrane/core/router/hotdeploy/DefaultHotDeployer.java +++ b/core/src/main/java/com/predic8/membrane/core/router/hotdeploy/DefaultHotDeployer.java @@ -46,16 +46,21 @@ private void startInternal() { return; } - if (!(router.getBeanFactory() instanceof TrackingApplicationContext tac)) { - log.warn(""" - ApplicationContext is not a TrackingApplicationContext. Please set . - """); + // Start from XML + if (router.getBeanFactory() != null) { + if (!(router.getBeanFactory() instanceof TrackingApplicationContext tac)) { + log.warn(""" + ApplicationContext is not a TrackingApplicationContext. Please set . + """); + return; + } + hdt = new HotDeploymentThread(router.getRef()); + hdt.setFiles(tac.getFiles()); + hdt.start(); return; } - hdt = new HotDeploymentThread(router.getRef()); - hdt.setFiles(tac.getFiles()); - hdt.start(); + log.debug("Hot deployment is not yet supported for the YAML configuration."); } } From 1fcf6f7a8626f17e792e9d6b0d024e14ba807f09 Mon Sep 17 00:00:00 2001 From: Thomas Bayer Date: Fri, 2 Jan 2026 18:39:53 +0100 Subject: [PATCH 3/5] refactor: improve JMX lifecycle management and HotDeployer YAML support - Replace `DefaultRouter` with `Router` in `JmxRouter` for enhanced abstraction. - Introduce `JMX_NAMESPACE` for improved consistency in bean names. - Enhance `JmxExporter` with static factory methods and improved `Router` integration. - Update `HotDeployer` to provide debug logging for unsupported YAML configurations. --- .../AuthorizationService.java | 72 ++++++++----------- .../MicrosoftEntraIDAuthorizationService.java | 34 ++++----- .../oauth2server/LoginDialog2.java | 6 +- .../session/JwtSessionManager.java | 2 +- .../membrane/core/jmx/JmxExporter.java | 7 +- .../membrane/core/proxies/SOAPProxy.java | 6 -- .../core/router/DefaultMainComponents.java | 2 +- .../jwt/JwtAuthInterceptorTest.java | 2 +- .../membrane/core/router/DummyTestRouter.java | 6 ++ .../core/security/JWTSecuritySchemeTest.java | 2 +- .../core/transport/ssl/SSLContextTest.java | 3 +- 11 files changed, 62 insertions(+), 80 deletions(-) diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/AuthorizationService.java b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/AuthorizationService.java index 4ff0a8bad9..41a49703c5 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/AuthorizationService.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/AuthorizationService.java @@ -13,52 +13,38 @@ package com.predic8.membrane.core.interceptor.oauth2.authorizationservice; -import com.predic8.membrane.annot.MCAttribute; -import com.predic8.membrane.annot.MCChildElement; -import com.predic8.membrane.core.config.security.SSLParser; -import com.predic8.membrane.core.exchange.Exchange; -import com.predic8.membrane.core.http.Request; -import com.predic8.membrane.core.http.Response; -import com.predic8.membrane.core.interceptor.oauth2.OAuth2TokenBody; -import com.predic8.membrane.core.interceptor.oauth2.tokengenerators.JwtGenerator; -import com.predic8.membrane.core.interceptor.oauth2client.rf.LogHelper; -import com.predic8.membrane.core.interceptor.oauth2client.rf.OAuth2Exception; -import com.predic8.membrane.core.interceptor.oauth2client.rf.OAuth2TokenResponseBody; -import com.predic8.membrane.core.interceptor.oauth2client.rf.token.JWSSigner; -import com.predic8.membrane.core.interceptor.session.Session; -import com.predic8.membrane.core.resolver.ResolverMap; +import com.predic8.membrane.annot.*; +import com.predic8.membrane.core.config.security.*; +import com.predic8.membrane.core.exchange.*; +import com.predic8.membrane.core.http.*; +import com.predic8.membrane.core.interceptor.oauth2.*; +import com.predic8.membrane.core.interceptor.oauth2.tokengenerators.*; +import com.predic8.membrane.core.interceptor.oauth2client.rf.*; +import com.predic8.membrane.core.interceptor.oauth2client.rf.token.*; +import com.predic8.membrane.core.interceptor.session.*; +import com.predic8.membrane.core.resolver.*; import com.predic8.membrane.core.router.*; -import com.predic8.membrane.core.transport.http.HttpClient; -import com.predic8.membrane.core.transport.http.client.HttpClientConfiguration; -import com.predic8.membrane.core.transport.ssl.PEMSupport; -import com.predic8.membrane.core.transport.ssl.SSLContext; -import com.predic8.membrane.core.transport.ssl.StaticSSLContext; -import jakarta.mail.internet.ParseException; -import org.jose4j.jwt.JwtClaims; -import org.jose4j.jwt.MalformedClaimException; -import org.jose4j.jwt.NumericDate; -import org.jose4j.lang.JoseException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.Nullable; -import javax.annotation.concurrent.GuardedBy; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; -import java.util.UUID; - -import static com.predic8.membrane.core.Constants.USERAGENT; +import com.predic8.membrane.core.transport.http.*; +import com.predic8.membrane.core.transport.http.client.*; +import com.predic8.membrane.core.transport.ssl.*; +import jakarta.mail.internet.*; +import org.jose4j.jwt.*; +import org.jose4j.lang.*; +import org.slf4j.*; + +import javax.annotation.*; +import javax.annotation.concurrent.*; +import java.io.*; +import java.util.*; + +import static com.predic8.membrane.core.Constants.*; import static com.predic8.membrane.core.http.Header.*; -import static com.predic8.membrane.core.http.MimeType.APPLICATION_JSON; -import static com.predic8.membrane.core.http.MimeType.APPLICATION_X_WWW_FORM_URLENCODED; -import static com.predic8.membrane.core.http.Request.get; -import static com.predic8.membrane.core.http.Response.badRequest; -import static com.predic8.membrane.core.http.Response.internalServerError; -import static com.predic8.membrane.core.interceptor.oauth2.OAuth2TokenBody.authorizationCodeBodyBuilder; -import static com.predic8.membrane.core.interceptor.oauth2.OAuth2TokenBody.refreshTokenBodyBuilder; +import static com.predic8.membrane.core.http.MimeType.*; +import static com.predic8.membrane.core.http.Request.*; +import static com.predic8.membrane.core.http.Response.*; +import static com.predic8.membrane.core.interceptor.oauth2.OAuth2TokenBody.*; import static com.predic8.membrane.core.interceptor.oauth2client.rf.JsonUtils.isJson; -import static org.apache.commons.codec.binary.Base64.encodeBase64; +import static org.apache.commons.codec.binary.Base64.*; public abstract class AuthorizationService { diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/MicrosoftEntraIDAuthorizationService.java b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/MicrosoftEntraIDAuthorizationService.java index 2a82ed2926..cb99c1f7ba 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/MicrosoftEntraIDAuthorizationService.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2/authorizationservice/MicrosoftEntraIDAuthorizationService.java @@ -13,23 +13,17 @@ package com.predic8.membrane.core.interceptor.oauth2.authorizationservice; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.predic8.membrane.annot.MCAttribute; -import com.predic8.membrane.annot.MCElement; -import com.predic8.membrane.annot.Required; -import com.predic8.membrane.core.interceptor.oauth2.OAuth2Util; -import com.predic8.membrane.core.interceptor.oauth2.parameter.ClaimsParameter; -import org.apache.commons.io.IOUtils; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; +import com.fasterxml.jackson.core.type.*; +import com.fasterxml.jackson.databind.*; +import com.predic8.membrane.annot.*; +import com.predic8.membrane.core.interceptor.oauth2.*; +import com.predic8.membrane.core.interceptor.oauth2.parameter.*; +import org.apache.commons.io.*; +import org.jetbrains.annotations.*; + +import java.io.*; +import java.util.*; +import java.util.stream.*; /** * Configure Membrane with Microsoft's Entra ID platform. @@ -72,12 +66,12 @@ public String getIssuer() { } @Override - public String getJwksEndpoint() throws Exception { + public String getJwksEndpoint() { return jwksEndpoint; } @Override - public String getEndSessionEndpoint() throws Exception { + public String getEndSessionEndpoint() { return endSessionEndpoint; } @@ -93,7 +87,7 @@ public void setScope(String scope) { encodedScope = false; } - private void adjustScope() throws UnsupportedEncodingException { + private void adjustScope() { if(scope == null) scope = "openid"; if (!encodedScope) { diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2server/LoginDialog2.java b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2server/LoginDialog2.java index 3f1f67b616..73862dcec2 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2server/LoginDialog2.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/oauth2server/LoginDialog2.java @@ -308,11 +308,11 @@ private Map doubleStringArrayToMap(String[] strings) { return result; } - private String[] prepareClaimsFromSession(Session s) throws UnsupportedEncodingException { + private String[] prepareClaimsFromSession(Session s) { return prepareStringArray(decodeClaimsFromSession(s)); } - private String[] prepareScopesFromSession(Session s) throws UnsupportedEncodingException { + private String[] prepareScopesFromSession(Session s) { return prepareStringArray(decodeScopesFromSession(s)); } @@ -345,7 +345,7 @@ private String[] decodeScopesFromSession(Session s) { return new String[0]; } - public Outcome redirectToLogin(Exchange exc) throws UnsupportedEncodingException { + public Outcome redirectToLogin(Exchange exc) { exc.setResponse(Response .redirect(path + "?target=" + URLEncoder.encode(exc.getOriginalRequestUri(), UTF_8), 302) .dontCache() diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/session/JwtSessionManager.java b/core/src/main/java/com/predic8/membrane/core/interceptor/session/JwtSessionManager.java index 548333b165..ec078595e7 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/session/JwtSessionManager.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/session/JwtSessionManager.java @@ -68,7 +68,7 @@ public void init(Router router) throws Exception { if (jwk == null) { rsaJsonWebKey = generateKey(); log.warn(""" - jwtSessionManager uses a generated key ('{}'). Sessions of this instance + jwtSessionManager uses a generated key ('{}'). Sessions of this instance will not be compatible with sessions of other (e.g. restarted) instances. To solve this, write the JWK into a file and reference it using . """, rsaJsonWebKey.toJson(INCLUDE_PRIVATE)); diff --git a/core/src/main/java/com/predic8/membrane/core/jmx/JmxExporter.java b/core/src/main/java/com/predic8/membrane/core/jmx/JmxExporter.java index ffc70223ab..ccea96a942 100644 --- a/core/src/main/java/com/predic8/membrane/core/jmx/JmxExporter.java +++ b/core/src/main/java/com/predic8/membrane/core/jmx/JmxExporter.java @@ -99,7 +99,10 @@ public static Optional getExporter(Router router) { if (router.getBeanFactory() == null) { return Optional.empty(); } - return Optional.of(router.getBeanFactory().getBean(JMX_EXPORTER_NAME, JmxExporter.class)); + try { + return Optional.of(router.getBeanFactory().getBean(JMX_EXPORTER_NAME, JmxExporter.class)); + } catch (NoSuchBeanDefinitionException e) { + return Optional.empty(); + } } - } diff --git a/core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java b/core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java index 581b8bd2e6..ed1de4c56b 100644 --- a/core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java +++ b/core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java @@ -154,7 +154,6 @@ private void configureRewritingOfPath(String targetPath) { RewriteInterceptor ri = new RewriteInterceptor(); ri.setMappings(Lists.newArrayList(new RewriteInterceptor.Mapping("^" + Pattern.quote(key.getPath()), Matcher.quoteReplacement(targetPath), "rewrite"))); interceptors.addFirst(ri); - automaticallyAddedInterceptorCount++; } private static @NotNull String getTargetPath(URL url) { @@ -272,13 +271,10 @@ private static Port getPortByNamespace(List ports, String namespace) { return null; } - private int automaticallyAddedInterceptorCount; - private void addWSDLInterceptor() { if (getFirstInterceptorOfType(WSDLInterceptor.class).isEmpty()) { WSDLInterceptor wsdlInterceptor = new WSDLInterceptor(); interceptors.addFirst(wsdlInterceptor); - automaticallyAddedInterceptorCount++; } } @@ -324,7 +320,6 @@ private void addWebServiceExplorer() { sui.setWsdl(wsdl); sui.setPortName(portName); interceptors.addFirst(sui); - automaticallyAddedInterceptorCount++; } private void addWSDLPublisherInterceptor() { @@ -335,7 +330,6 @@ private void addWSDLPublisherInterceptor() { wp.setWsdl(wsdl); wp.init(router); interceptors.addFirst(wp); - automaticallyAddedInterceptorCount++; } private boolean hasWSDLPublisherInterceptor() { diff --git a/core/src/main/java/com/predic8/membrane/core/router/DefaultMainComponents.java b/core/src/main/java/com/predic8/membrane/core/router/DefaultMainComponents.java index 995f5cc78d..ac88013f69 100644 --- a/core/src/main/java/com/predic8/membrane/core/router/DefaultMainComponents.java +++ b/core/src/main/java/com/predic8/membrane/core/router/DefaultMainComponents.java @@ -66,7 +66,7 @@ public void init() { registry = new BeanRegistryImplementation(null, router, null); } - registry.registerIfAbsent(HttpClientConfiguration.class, () -> new HttpClientConfiguration()); + registry.registerIfAbsent(HttpClientConfiguration.class, HttpClientConfiguration::new); registry.registerIfAbsent(ResolverMap.class, () -> { ResolverMap rs = new ResolverMap(httpClientFactory, kubernetesClientFactory); diff --git a/core/src/test/java/com/predic8/membrane/core/interceptor/jwt/JwtAuthInterceptorTest.java b/core/src/test/java/com/predic8/membrane/core/interceptor/jwt/JwtAuthInterceptorTest.java index 9b444f5b6b..d9745e415f 100644 --- a/core/src/test/java/com/predic8/membrane/core/interceptor/jwt/JwtAuthInterceptorTest.java +++ b/core/src/test/java/com/predic8/membrane/core/interceptor/jwt/JwtAuthInterceptorTest.java @@ -250,7 +250,7 @@ void test(TestData data) throws Exception{ data.asserts().accept(exc); } - private JwtAuthInterceptor prepareInterceptor(RsaJsonWebKey publicOnly) throws Exception { + private JwtAuthInterceptor prepareInterceptor(RsaJsonWebKey publicOnly) { return initInterceptor(createInterceptor(publicOnly)); } diff --git a/core/src/test/java/com/predic8/membrane/core/router/DummyTestRouter.java b/core/src/test/java/com/predic8/membrane/core/router/DummyTestRouter.java index 8301b17853..8a68eaf89f 100644 --- a/core/src/test/java/com/predic8/membrane/core/router/DummyTestRouter.java +++ b/core/src/test/java/com/predic8/membrane/core/router/DummyTestRouter.java @@ -14,6 +14,7 @@ package com.predic8.membrane.core.router; +import com.predic8.membrane.annot.beanregistry.*; import com.predic8.membrane.core.exchangestore.*; import com.predic8.membrane.core.interceptor.*; import com.predic8.membrane.core.kubernetes.client.*; @@ -115,6 +116,11 @@ public DNSCache getDnsCache() { return dnsCache; } + @Override + public BeanRegistry getRegistry() { + throw new UnsupportedOperationException("DummyTestRouter does not have a BeanRegistry."); + } + @Override public HttpTransport getTransport() { return transport; diff --git a/core/src/test/java/com/predic8/membrane/core/security/JWTSecuritySchemeTest.java b/core/src/test/java/com/predic8/membrane/core/security/JWTSecuritySchemeTest.java index 5e9b98b1a1..453d5e5952 100644 --- a/core/src/test/java/com/predic8/membrane/core/security/JWTSecuritySchemeTest.java +++ b/core/src/test/java/com/predic8/membrane/core/security/JWTSecuritySchemeTest.java @@ -50,7 +50,7 @@ private JwtAuthInterceptor prepareInterceptor(RsaJsonWebKey publicOnly) throws E return initInterceptor(createInterceptor(publicOnly)); } - private JwtAuthInterceptor initInterceptor(JwtAuthInterceptor interceptor) throws Exception { + private JwtAuthInterceptor initInterceptor(JwtAuthInterceptor interceptor) { interceptor.init(new DummyTestRouter()); return interceptor; } diff --git a/core/src/test/java/com/predic8/membrane/core/transport/ssl/SSLContextTest.java b/core/src/test/java/com/predic8/membrane/core/transport/ssl/SSLContextTest.java index e7f3e89695..2042a14624 100644 --- a/core/src/test/java/com/predic8/membrane/core/transport/ssl/SSLContextTest.java +++ b/core/src/test/java/com/predic8/membrane/core/transport/ssl/SSLContextTest.java @@ -245,8 +245,7 @@ public void readPEMFiles() throws Exception { cert.setContent(Resources.toString(getResource("ca/server.pem"), UTF_8)); key.setCertificates(List.of(cert)); sslParser.setKey(key); - StaticSSLContext ctx = new StaticSSLContext(sslParser, new ResolverMap(), ""); - return ctx; + return new StaticSSLContext(sslParser, new ResolverMap(), ""); } private static @NotNull StaticSSLContext createPEMClientSSLContext() throws IOException { From 16b3c221f8667c172c8dc1bef923e2c6ae1eb2ec Mon Sep 17 00:00:00 2001 From: Thomas Bayer Date: Fri, 2 Jan 2026 19:05:20 +0100 Subject: [PATCH 4/5] refactor: streamline JMX integration and lifecycle handling - Remove unused methods and imports from `DefaultRouter`, `JmxRouter`, and `Configuration`. - Simplify `JmxExporter` by replacing `MBeanExporter` inheritance and improving lifecycle checks with `exporter` nullability. - Optimize `addRouter()` in `JmxExporter` by removing redundant exception handling. --- .../predic8/membrane/core/jmx/JmxExporter.java | 15 ++++++--------- .../com/predic8/membrane/core/jmx/JmxRouter.java | 1 - .../membrane/core/router/Configuration.java | 1 - .../membrane/core/router/DefaultRouter.java | 13 +------------ 4 files changed, 7 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/com/predic8/membrane/core/jmx/JmxExporter.java b/core/src/main/java/com/predic8/membrane/core/jmx/JmxExporter.java index ccea96a942..9c8a73894e 100644 --- a/core/src/main/java/com/predic8/membrane/core/jmx/JmxExporter.java +++ b/core/src/main/java/com/predic8/membrane/core/jmx/JmxExporter.java @@ -27,9 +27,9 @@ import static org.springframework.jmx.support.RegistrationPolicy.*; @MCElement(name = JmxExporter.JMX_EXPORTER_NAME) -public class JmxExporter extends MBeanExporter implements Lifecycle { +public class JmxExporter implements Lifecycle { - private static final Logger log = LoggerFactory.getLogger(MBeanExporter.class); + private static final Logger log = LoggerFactory.getLogger(JmxExporter.class); public static final String JMX_EXPORTER_NAME = "jmxExporter"; public static final String JMX_NAMESPACE = "io.membrane-api"; @@ -52,11 +52,12 @@ public void start() { public void stop() { jmxBeans.clear(); exporter.destroy(); + exporter = null; } @Override public boolean isRunning() { - return false; + return exporter != null; } public void addBean(String fullyQualifiedMBeanName, Object bean) { @@ -74,12 +75,8 @@ public void initAfterBeansAdded() { } public void addRouter(Router router) { - try { - addBean(JMX_NAMESPACE + ":00=routers, name=" + router.getConfiguration().getJmx(), new JmxRouter(router, this)); - initAfterBeansAdded(); - } catch (NoSuchBeanDefinitionException ignored) { - // If bean is not available do not init jmx - } + addBean(JMX_NAMESPACE + ":00=routers, name=" + router.getConfiguration().getJmx(), new JmxRouter(router, this)); + initAfterBeansAdded(); } diff --git a/core/src/main/java/com/predic8/membrane/core/jmx/JmxRouter.java b/core/src/main/java/com/predic8/membrane/core/jmx/JmxRouter.java index 051e9344fe..bd1ef996e9 100644 --- a/core/src/main/java/com/predic8/membrane/core/jmx/JmxRouter.java +++ b/core/src/main/java/com/predic8/membrane/core/jmx/JmxRouter.java @@ -22,7 +22,6 @@ @ManagedResource() public class JmxRouter { - private final Router router; private final JmxExporter exporter; diff --git a/core/src/main/java/com/predic8/membrane/core/router/Configuration.java b/core/src/main/java/com/predic8/membrane/core/router/Configuration.java index 2e2f9659ab..e9a6c839cf 100644 --- a/core/src/main/java/com/predic8/membrane/core/router/Configuration.java +++ b/core/src/main/java/com/predic8/membrane/core/router/Configuration.java @@ -148,7 +148,6 @@ public URIFactory getUriFactory() { * @description Base location for the router's configuration file. * @param baseLocation The base directory path used to resolve relative file paths in configuration */ - @MCAttribute() public void setBaseLocation(String baseLocation) { this.baseLocation = baseLocation; } diff --git a/core/src/main/java/com/predic8/membrane/core/router/DefaultRouter.java b/core/src/main/java/com/predic8/membrane/core/router/DefaultRouter.java index 8f847e4ce6..a3136d61a5 100644 --- a/core/src/main/java/com/predic8/membrane/core/router/DefaultRouter.java +++ b/core/src/main/java/com/predic8/membrane/core/router/DefaultRouter.java @@ -16,7 +16,6 @@ import com.predic8.membrane.annot.*; import com.predic8.membrane.annot.beanregistry.*; -import com.predic8.membrane.core.proxies.RuleManager.*; import com.predic8.membrane.core.cli.*; import com.predic8.membrane.core.config.spring.*; import com.predic8.membrane.core.exchangestore.*; @@ -28,6 +27,7 @@ import com.predic8.membrane.core.openapi.*; import com.predic8.membrane.core.openapi.serviceproxy.*; import com.predic8.membrane.core.proxies.*; +import com.predic8.membrane.core.proxies.RuleManager.*; import com.predic8.membrane.core.resolver.*; import com.predic8.membrane.core.router.hotdeploy.*; import com.predic8.membrane.core.transport.*; @@ -46,7 +46,6 @@ import java.util.*; import static com.predic8.membrane.core.proxies.RuleManager.RuleDefinitionSource.*; -import static com.predic8.membrane.core.jmx.JmxExporter.*; import static com.predic8.membrane.core.util.DLPUtil.*; /* @@ -278,16 +277,6 @@ public void add(Proxy proxy) throws IOException { } - private Optional getExporter() { - var exporter= mainComponents.getRegistry().getBean(JmxExporter.class); - if (exporter.isPresent()) return exporter; - if (mainComponents.getBeanFactory() == null) { - return Optional.empty(); - } - return Optional.of(mainComponents.getBeanFactory().getBean(JMX_EXPORTER_NAME, JmxExporter.class)); - } - - @Override public void stop() { getRegistry().getBean(KubernetesWatcher.class).ifPresent(KubernetesWatcher::stop); From fdb62699b45bf0889ae0a319f61a13722b6d01a5 Mon Sep 17 00:00:00 2001 From: Thomas Bayer Date: Fri, 2 Jan 2026 19:24:01 +0100 Subject: [PATCH 5/5] extend: increase test timeout in `MassivelyParallelTest` and update JMX namespace in roadmap --- .../integration/withoutinternet/MassivelyParallelTest.java | 2 +- docs/ROADMAP.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/test/java/com/predic8/membrane/integration/withoutinternet/MassivelyParallelTest.java b/core/src/test/java/com/predic8/membrane/integration/withoutinternet/MassivelyParallelTest.java index ad82dd7559..570a906a07 100644 --- a/core/src/test/java/com/predic8/membrane/integration/withoutinternet/MassivelyParallelTest.java +++ b/core/src/test/java/com/predic8/membrane/integration/withoutinternet/MassivelyParallelTest.java @@ -102,7 +102,7 @@ private void runInParallel(Consumer job, int threadCount) { es.submit(() -> job.accept(cdl)); } es.shutdown(); - if (!es.awaitTermination(60, SECONDS)) { + if (!es.awaitTermination(120, SECONDS)) { es.shutdownNow(); fail("Tasks did not complete within timeout"); } diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 1f14ba2e27..5f6c298787 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -91,6 +91,7 @@ - YAML Configuration as default - Use of colors in logs - Removed camelCase conversion of header access in Groovy scripts instead of header.contentType use header['Content-Type'] +- JMX namespace changed from org.membrane-soa to io.membrane-api. ## Minor - Rewrite JSONAssert Tests with RESTAssured