diff --git a/sermant-integration-tests/dubbo-test/dubbo-integration-api/src/main/java/io/sermant/integration/entity/LaneTestEntity.java b/sermant-integration-tests/dubbo-test/dubbo-integration-api/src/main/java/io/sermant/integration/entity/LaneTestEntity.java index 20bcea6628..9e4eb32285 100644 --- a/sermant-integration-tests/dubbo-test/dubbo-integration-api/src/main/java/io/sermant/integration/entity/LaneTestEntity.java +++ b/sermant-integration-tests/dubbo-test/dubbo-integration-api/src/main/java/io/sermant/integration/entity/LaneTestEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2023-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ public class LaneTestEntity implements Serializable { private final boolean enabled; /** - * 构造方法 + * constructor * * @param id id * @param enabled enabled diff --git a/sermant-integration-tests/dubbo-test/dubbo-integration-test/src/test/java/io/sermant/integration/lane/LaneTest.java b/sermant-integration-tests/dubbo-test/dubbo-integration-test/src/test/java/io/sermant/integration/lane/LaneTest.java index bca4fdc950..3dc7ebe037 100644 --- a/sermant-integration-tests/dubbo-test/dubbo-integration-test/src/test/java/io/sermant/integration/lane/LaneTest.java +++ b/sermant-integration-tests/dubbo-test/dubbo-integration-test/src/test/java/io/sermant/integration/lane/LaneTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2023-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,7 +53,7 @@ public class LaneTest { private final boolean isExecuteSpringTest; /** - * 构造方法 + * constructor */ public LaneTest() { baseUrl = "http://127.0.0.1:" + System.getProperty("controller.port", "28019") + "/controller/getLaneBy"; diff --git a/sermant-integration-tests/dubbo-test/dubbo-integration-test/src/test/java/io/sermant/integration/registry/ConsumerTest.java b/sermant-integration-tests/dubbo-test/dubbo-integration-test/src/test/java/io/sermant/integration/registry/ConsumerTest.java index 8d976fceee..66e289617c 100644 --- a/sermant-integration-tests/dubbo-test/dubbo-integration-test/src/test/java/io/sermant/integration/registry/ConsumerTest.java +++ b/sermant-integration-tests/dubbo-test/dubbo-integration-test/src/test/java/io/sermant/integration/registry/ConsumerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,7 +41,7 @@ public class ConsumerTest { private final String dubboVersion; /** - * 构造方法 + * constructor */ public ConsumerTest() { dubboVersion = System.getProperty("dubbo.running.version"); diff --git a/sermant-integration-tests/dubbo-test/dubbo-integration-test/src/test/java/io/sermant/integration/registry/SpringAndDubboTest.java b/sermant-integration-tests/dubbo-test/dubbo-integration-test/src/test/java/io/sermant/integration/registry/SpringAndDubboTest.java index 9d7058e477..579b233cff 100644 --- a/sermant-integration-tests/dubbo-test/dubbo-integration-test/src/test/java/io/sermant/integration/registry/SpringAndDubboTest.java +++ b/sermant-integration-tests/dubbo-test/dubbo-integration-test/src/test/java/io/sermant/integration/registry/SpringAndDubboTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ public class SpringAndDubboTest { private final String baseUrl; /** - * 构造方法 + * constructor */ public SpringAndDubboTest() { baseUrl = "http://127.0.0.1:" + System.getProperty("controller.port", "28020") + "/consumer/"; diff --git a/sermant-integration-tests/dubbo-test/dubbo-integration-test/src/test/java/io/sermant/integration/router/RouterTest.java b/sermant-integration-tests/dubbo-test/dubbo-integration-test/src/test/java/io/sermant/integration/router/RouterTest.java index 616074174e..21cbc3af47 100644 --- a/sermant-integration-tests/dubbo-test/dubbo-integration-test/src/test/java/io/sermant/integration/router/RouterTest.java +++ b/sermant-integration-tests/dubbo-test/dubbo-integration-test/src/test/java/io/sermant/integration/router/RouterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,7 +60,7 @@ public class RouterTest { private final boolean isExecuteSpringTest; /** - * 构造方法 + * constructor */ public RouterTest() throws InterruptedException { testTagRouterBaseUrl = diff --git a/sermant-integration-tests/spring-test/spring-integration-test/src/test/java/io/sermant/integration/lane/LaneTest.java b/sermant-integration-tests/spring-test/spring-integration-test/src/test/java/io/sermant/integration/lane/LaneTest.java index 40fb609f6f..609238bdff 100644 --- a/sermant-integration-tests/spring-test/spring-integration-test/src/test/java/io/sermant/integration/lane/LaneTest.java +++ b/sermant-integration-tests/spring-test/spring-integration-test/src/test/java/io/sermant/integration/lane/LaneTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2023-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -90,7 +90,7 @@ public class LaneTest { private final boolean shouldTestWebclient; /** - * 构造方法 + * constructor */ public LaneTest() { springCloudVersion = Optional.ofNullable(System.getenv("SPRING_CLOUD_VERSION")).orElse("Hoxton.RELEASE"); diff --git a/sermant-integration-tests/spring-test/spring-integration-test/src/test/java/io/sermant/integration/router/TagRouterTest.java b/sermant-integration-tests/spring-test/spring-integration-test/src/test/java/io/sermant/integration/router/TagRouterTest.java index 071ad79188..4950d2a4b9 100644 --- a/sermant-integration-tests/spring-test/spring-integration-test/src/test/java/io/sermant/integration/router/TagRouterTest.java +++ b/sermant-integration-tests/spring-test/spring-integration-test/src/test/java/io/sermant/integration/router/TagRouterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -92,7 +92,7 @@ public class TagRouterTest { private final String springCloudVersion; /** - * 构造方法 + * constructor */ public TagRouterTest() throws InterruptedException { springCloudVersion = Optional.ofNullable(System.getenv("SPRING_CLOUD_VERSION")).orElse("Hoxton.RELEASE"); diff --git a/sermant-plugins/sermant-flowcontrol/flowcontrol-plugin/src/main/java/io/sermant/flowcontrol/DispatcherServletInterceptor.java b/sermant-plugins/sermant-flowcontrol/flowcontrol-plugin/src/main/java/io/sermant/flowcontrol/DispatcherServletInterceptor.java index 8d2c361537..93f550bf41 100644 --- a/sermant-plugins/sermant-flowcontrol/flowcontrol-plugin/src/main/java/io/sermant/flowcontrol/DispatcherServletInterceptor.java +++ b/sermant-plugins/sermant-flowcontrol/flowcontrol-plugin/src/main/java/io/sermant/flowcontrol/DispatcherServletInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,17 +18,23 @@ import io.sermant.core.plugin.agent.entity.ExecuteContext; import io.sermant.core.utils.LogUtils; +import io.sermant.core.utils.ReflectUtils; import io.sermant.flowcontrol.common.config.ConfigConst; import io.sermant.flowcontrol.common.entity.FlowControlResult; import io.sermant.flowcontrol.common.entity.HttpRequestEntity; import io.sermant.flowcontrol.common.entity.RequestEntity.RequestType; import io.sermant.flowcontrol.service.InterceptorSupporter; +import java.io.IOException; +import java.io.PrintWriter; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -42,6 +48,28 @@ public class DispatcherServletInterceptor extends InterceptorSupporter { private final String className = DispatcherServletInterceptor.class.getName(); + private Function getRequestUri; + + private Function getPathInfo; + + private Function getMethod; + + private Function> getHeaderNames; + + private BiFunction getHeader; + + private Function getWriter; + + private BiConsumer setStatus; + + /** + * constructor + */ + public DispatcherServletInterceptor() { + super(); + initFunction(); + } + /** * http request data conversion adapts to plugin -> service data transfer Note that this method is not * extractable,Because host dependencies can only be loaded by this interceptor, pulling out results in classes not @@ -50,18 +78,18 @@ public class DispatcherServletInterceptor extends InterceptorSupporter { * @param request request * @return HttpRequestEntity */ - private Optional convertToHttpEntity(HttpServletRequest request) { + private Optional convertToHttpEntity(Object request) { if (request == null) { return Optional.empty(); } - String uri = request.getRequestURI(); + String uri = getRequestUri.apply(request); return Optional.of(new HttpRequestEntity.Builder() .setRequestType(RequestType.SERVER) - .setPathInfo(request.getPathInfo()) + .setPathInfo(getPathInfo.apply(request)) .setServletPath(uri) .setHeaders(getHeaders(request)) - .setMethod(request.getMethod()) - .setServiceName(request.getHeader(ConfigConst.FLOW_REMOTE_SERVICE_NAME_HEADER_KEY)) + .setMethod(getMethod.apply(request)) + .setServiceName(getHeader.apply(request, ConfigConst.FLOW_REMOTE_SERVICE_NAME_HEADER_KEY)) .build()); } @@ -71,12 +99,12 @@ private Optional convertToHttpEntity(HttpServletRequest reque * @param request request information * @return headers */ - private Map getHeaders(HttpServletRequest request) { - final Enumeration headerNames = request.getHeaderNames(); + private Map getHeaders(Object request) { + final Enumeration headerNames = getHeaderNames.apply(request); final Map headers = new HashMap<>(); while (headerNames.hasMoreElements()) { final String headerName = headerNames.nextElement(); - headers.put(headerName, request.getHeader(headerName)); + headers.put(headerName, getHeader.apply(request, headerName)); } return Collections.unmodifiableMap(headers); } @@ -85,19 +113,19 @@ private Map getHeaders(HttpServletRequest request) { protected final ExecuteContext doBefore(ExecuteContext context) throws Exception { LogUtils.printHttpRequestBeforePoint(context); final Object[] allArguments = context.getArguments(); - final HttpServletRequest argument = (HttpServletRequest) allArguments[0]; + final Object request = allArguments[0]; final FlowControlResult result = new FlowControlResult(); - final Optional httpRequestEntity = convertToHttpEntity(argument); + final Optional httpRequestEntity = convertToHttpEntity(request); if (!httpRequestEntity.isPresent()) { return context; } chooseHttpService().onBefore(className, httpRequestEntity.get(), result); if (result.isSkip()) { context.skip(null); - final HttpServletResponse response = (HttpServletResponse) allArguments[1]; + final Object response = allArguments[1]; if (response != null) { - response.setStatus(result.getResponse().getCode()); - response.getWriter().print(result.buildResponseMsg()); + setStatus.accept(response, result.getResponse().getCode()); + getWriter.apply(response).print(result.buildResponseMsg()); } } return context; @@ -116,4 +144,75 @@ protected final ExecuteContext doThrow(ExecuteContext context) { LogUtils.printHttpRequestOnThrowPoint(context); return context; } + + private String getRequestUri(Object httpServletRequest) { + return getString(httpServletRequest, "getRequestURI"); + } + + private String getPathInfo(Object httpServletRequest) { + return getString(httpServletRequest, "getPathInfo"); + } + + private String getMethod(Object httpServletRequest) { + return getString(httpServletRequest, "getMethod"); + } + + private Enumeration getHeaderNames(Object httpServletRequest) { + return (Enumeration) ReflectUtils.invokeMethodWithNoneParameter(httpServletRequest, "getHeaderNames") + .orElse(null); + } + + private String getHeader(Object httpServletRequest, String key) { + return (String) ReflectUtils.invokeMethod(httpServletRequest, "getHeader", new Class[]{String.class}, + new Object[]{key}).orElse(null); + } + + private PrintWriter getWriter(Object httpServletRequest) { + return (PrintWriter) ReflectUtils.invokeMethodWithNoneParameter(httpServletRequest, "getWriter") + .orElse(null); + } + + private void setStatus(Object httpServletResponse, int code) { + ReflectUtils.invokeMethod(httpServletResponse, "setStatus", new Class[]{int.class}, new Object[]{code}); + } + + private String getString(Object object, String method) { + return (String) ReflectUtils.invokeMethodWithNoneParameter(object, method).orElse(null); + } + + private void initFunction() { + boolean canLoadLowVersion = canLoadLowVersion(); + if (canLoadLowVersion) { + getRequestUri = obj -> ((HttpServletRequest) obj).getRequestURI(); + getPathInfo = obj -> ((HttpServletRequest) obj).getPathInfo(); + getMethod = obj -> ((HttpServletRequest) obj).getMethod(); + getHeaderNames = obj -> ((HttpServletRequest) obj).getHeaderNames(); + getHeader = (obj, key) -> ((HttpServletRequest) obj).getHeader(key); + getWriter = obj -> { + try { + return ((HttpServletResponse) obj).getWriter(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + }; + setStatus = (obj, code) -> ((HttpServletResponse) obj).setStatus(code); + } else { + getRequestUri = this::getRequestUri; + getPathInfo = this::getPathInfo; + getMethod = this::getMethod; + getHeaderNames = this::getHeaderNames; + getHeader = this::getHeader; + getWriter = this::getWriter; + setStatus = this::setStatus; + } + } + + private boolean canLoadLowVersion() { + try { + Class.forName(HttpServletRequest.class.getCanonicalName()); + } catch (NoClassDefFoundError | ClassNotFoundException error) { + return false; + } + return true; + } } diff --git a/sermant-plugins/sermant-loadbalancer/dubbo-loadbalancer-plugin/src/main/java/io/sermant/loadbalancer/interceptor/UrlInterceptor.java b/sermant-plugins/sermant-loadbalancer/dubbo-loadbalancer-plugin/src/main/java/io/sermant/loadbalancer/interceptor/UrlInterceptor.java index 56c8925306..515db64b54 100644 --- a/sermant-plugins/sermant-loadbalancer/dubbo-loadbalancer-plugin/src/main/java/io/sermant/loadbalancer/interceptor/UrlInterceptor.java +++ b/sermant-plugins/sermant-loadbalancer/dubbo-loadbalancer-plugin/src/main/java/io/sermant/loadbalancer/interceptor/UrlInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -66,7 +66,7 @@ public class UrlInterceptor extends AbstractInterceptor { private Set supportRules; /** - * 构造方法 + * constructor */ public UrlInterceptor() { config = PluginConfigManager.getPluginConfig(LoadbalancerConfig.class); diff --git a/sermant-plugins/sermant-loadbalancer/spring-cloud-loadbalancer-plugin/src/main/java/io/sermant/loadbalancer/declarer/ClientFactoryDeclarer.java b/sermant-plugins/sermant-loadbalancer/spring-cloud-loadbalancer-plugin/src/main/java/io/sermant/loadbalancer/declarer/ClientFactoryDeclarer.java index df985a63c4..b0e20d0bad 100644 --- a/sermant-plugins/sermant-loadbalancer/spring-cloud-loadbalancer-plugin/src/main/java/io/sermant/loadbalancer/declarer/ClientFactoryDeclarer.java +++ b/sermant-plugins/sermant-loadbalancer/spring-cloud-loadbalancer-plugin/src/main/java/io/sermant/loadbalancer/declarer/ClientFactoryDeclarer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ public class ClientFactoryDeclarer extends AbstractDeclarer { private static final String METHOD_NAME = "getInstance"; /** - * 构造方法 + * constructor */ public ClientFactoryDeclarer() { super(ENHANCE_CLASS, INTERCEPT_CLASS, METHOD_NAME); diff --git a/sermant-plugins/sermant-monitor/monitor-plugin/src/main/java/io/sermant/monitor/interceptor/DispatcherServletInterceptor.java b/sermant-plugins/sermant-monitor/monitor-plugin/src/main/java/io/sermant/monitor/interceptor/DispatcherServletInterceptor.java index c584783547..941be643db 100644 --- a/sermant-plugins/sermant-monitor/monitor-plugin/src/main/java/io/sermant/monitor/interceptor/DispatcherServletInterceptor.java +++ b/sermant-plugins/sermant-monitor/monitor-plugin/src/main/java/io/sermant/monitor/interceptor/DispatcherServletInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,9 +20,12 @@ import io.sermant.core.plugin.agent.entity.ExecuteContext; import io.sermant.core.plugin.agent.interceptor.AbstractInterceptor; import io.sermant.core.utils.LogUtils; +import io.sermant.core.utils.ReflectUtils; import io.sermant.monitor.common.MetricCalEntity; import io.sermant.monitor.util.MonitorCacheUtil; +import java.util.function.Function; + import javax.servlet.http.HttpServletRequest; /** @@ -34,6 +37,15 @@ public class DispatcherServletInterceptor extends AbstractInterceptor { private static final String START_TIME = "startTime"; + private Function getRequestUri; + + /** + * constructor + */ + public DispatcherServletInterceptor() { + initFunction(); + } + @Override public ExecuteContext before(ExecuteContext context) { LogUtils.printHttpRequestBeforePoint(context); @@ -50,7 +62,7 @@ public ExecuteContext after(ExecuteContext context) { LogUtils.printHttpRequestAfterPoint(context); return context; } - String uri = ((HttpServletRequest) context.getArguments()[0]).getRequestURI(); + String uri = getRequestUri.apply(context.getArguments()[0]); MetricCalEntity metricCalEntity = MonitorCacheUtil.getMetricCalEntity(uri); metricCalEntity.getReqNum().incrementAndGet(); long startTime = (Long) context.getExtMemberFieldValue(START_TIME); @@ -70,11 +82,33 @@ public ExecuteContext onThrow(ExecuteContext context) { LogUtils.printHttpRequestOnThrowPoint(context); return context; } - String uri = ((HttpServletRequest) context.getArguments()[0]).getRequestURI(); + String uri = getRequestUri.apply(context.getArguments()[0]); MetricCalEntity metricCalEntity = MonitorCacheUtil.getMetricCalEntity(uri); metricCalEntity.getReqNum().incrementAndGet(); metricCalEntity.getFailedReqNum().incrementAndGet(); LogUtils.printHttpRequestOnThrowPoint(context); return context; } + + private String getRequestUri(Object httpServletRequest) { + return (String) ReflectUtils.invokeMethodWithNoneParameter(httpServletRequest, "getRequestURI").orElse(null); + } + + private void initFunction() { + boolean canLoadLowVersion = canLoadLowVersion(); + if (canLoadLowVersion) { + getRequestUri = obj -> ((HttpServletRequest) obj).getRequestURI(); + } else { + getRequestUri = this::getRequestUri; + } + } + + private boolean canLoadLowVersion() { + try { + Class.forName(HttpServletRequest.class.getCanonicalName()); + } catch (NoClassDefFoundError | ClassNotFoundException error) { + return false; + } + return true; + } } diff --git a/sermant-plugins/sermant-router/dubbo3-router-plugin/src/main/java/io/sermant/router/dubbo/interceptor/ServiceDiscoveryRegistryDirectoryInterceptor.java b/sermant-plugins/sermant-router/dubbo3-router-plugin/src/main/java/io/sermant/router/dubbo/interceptor/ServiceDiscoveryRegistryDirectoryInterceptor.java index 8ca3102282..94d2285c5b 100644 --- a/sermant-plugins/sermant-router/dubbo3-router-plugin/src/main/java/io/sermant/router/dubbo/interceptor/ServiceDiscoveryRegistryDirectoryInterceptor.java +++ b/sermant-plugins/sermant-router/dubbo3-router-plugin/src/main/java/io/sermant/router/dubbo/interceptor/ServiceDiscoveryRegistryDirectoryInterceptor.java @@ -39,7 +39,7 @@ public class ServiceDiscoveryRegistryDirectoryInterceptor extends AbstractInterc private final AtomicBoolean isInitialized = new AtomicBoolean(); /** - * 构造方法 + * constructor */ public ServiceDiscoveryRegistryDirectoryInterceptor() { invokerRuleStrategyService = PluginServiceManager.getPluginService(InvokerRuleStrategyService.class); diff --git a/sermant-plugins/sermant-router/spring-router-plugin/pom.xml b/sermant-plugins/sermant-router/spring-router-plugin/pom.xml index d312b23a61..9ef34cb5d2 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/pom.xml +++ b/sermant-plugins/sermant-router/spring-router-plugin/pom.xml @@ -61,12 +61,6 @@ ${jakarta.el.version} provided - - org.springframework - spring-web - ${spring.version} - provided - org.springframework spring-webflux @@ -79,12 +73,6 @@ ${spring.version} provided - - org.springframework - spring-webflux - ${spring.version} - provided - io.projectreactor.netty reactor-netty diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/declarer/HandlerExecutionChainDeclarer.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/declarer/DispatcherServletDeclarer.java similarity index 70% rename from sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/declarer/HandlerExecutionChainDeclarer.java rename to sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/declarer/DispatcherServletDeclarer.java index 2d6d02d096..f0a2760367 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/declarer/HandlerExecutionChainDeclarer.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/declarer/DispatcherServletDeclarer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,23 +19,23 @@ import io.sermant.core.plugin.agent.matcher.ClassMatcher; /** - * Add an injection interceptor by intercepting and inject a spring web interceptor + * get http request data * * @author provenceee * @since 2022-07-12 */ -public class HandlerExecutionChainDeclarer extends AbstractDeclarer { - private static final String ENHANCE_CLASS = "org.springframework.web.servlet.HandlerExecutionChain"; +public class DispatcherServletDeclarer extends AbstractDeclarer { + private static final String ENHANCE_CLASS = "org.springframework.web.servlet.DispatcherServlet"; private static final String INTERCEPT_CLASS - = "io.sermant.router.spring.interceptor.HandlerExecutionChainInterceptor"; + = "io.sermant.router.spring.interceptor.DispatcherServletInterceptor"; - private static final String METHOD_NAME = "applyPreHandle"; + private static final String METHOD_NAME = "doService"; /** * Constructor */ - public HandlerExecutionChainDeclarer() { + public DispatcherServletDeclarer() { super(ENHANCE_CLASS, INTERCEPT_CLASS, METHOD_NAME); } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/entity/Keys.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/entity/Keys.java new file mode 100644 index 0000000000..fa594bc406 --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/entity/Keys.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2023-2024 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.sermant.router.spring.entity; + +import java.util.Set; + +/** + * Transparent transmission marks the key entity + * + * @author provenceee + * @since 2023-02-21 + */ +public class Keys { + private final Set matchedKeys; + + private final Set injectedTags; + + /** + * Constructor + * + * @param matchedKeys Label routing transparent transmission markers + * @param injectedTags Swim lane transparent markers + */ + public Keys(Set matchedKeys, Set injectedTags) { + this.matchedKeys = matchedKeys; + this.injectedTags = injectedTags; + } + + public Set getMatchedKeys() { + return matchedKeys; + } + + public Set getInjectedTags() { + return injectedTags; + } +} diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/AbstractHandler.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/AbstractHandler.java index 3ed1132c8c..bf3dcd6e08 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/AbstractHandler.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/AbstractHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2023-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ import io.sermant.router.common.handler.Handler; import io.sermant.router.common.utils.CollectionUtils; +import io.sermant.router.spring.entity.Keys; import java.util.Collections; import java.util.HashMap; @@ -51,4 +52,17 @@ protected Map> getRequestTag(Map> head } return map; } -} \ No newline at end of file + + /** + * Obtain transparent tags + * + * @param path The path of the request + * @param methodName http method + * @param headers HTTP request headers + * @param parameters URL parameter + * @param keys The key of the tag to be obtained + * @return Marks for transparent transmission + */ + public abstract Map> getRequestTag(String path, String methodName, + Map> headers, Map> parameters, Keys keys); +} diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/AbstractMappingHandler.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/AbstractMappingHandler.java deleted file mode 100644 index 707d1e4823..0000000000 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/AbstractMappingHandler.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.sermant.router.spring.handler; - -import io.sermant.core.plugin.service.PluginServiceManager; -import io.sermant.router.spring.service.SpringConfigService; - -import java.util.List; -import java.util.Map; - -/** - * AbstractHandlerMapping handler - * - * @author provenceee - * @since 2023-02-21 - */ -public abstract class AbstractMappingHandler extends AbstractHandler { - /** - * Configuration service - */ - protected final SpringConfigService configService; - - /** - * Constructor - */ - public AbstractMappingHandler() { - configService = PluginServiceManager.getPluginService(SpringConfigService.class); - } - - /** - * Obtain transparent tags - * - * @param path The path of the request - * @param methodName http method - * @param headers HTTP request headers - * @param parameters URL parameter - * @return Marks for transparent transmission - */ - public abstract Map> getRequestTag(String path, String methodName, - Map> headers, Map> parameters); -} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/AbstractRequestTagHandler.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/AbstractRequestTagHandler.java deleted file mode 100644 index 9119d9c16f..0000000000 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/AbstractRequestTagHandler.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.sermant.router.spring.handler; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Web Blocker handler - * - * @author provenceee - * @since 2023-02-21 - */ -public abstract class AbstractRequestTagHandler extends AbstractHandler { - /** - * Obtain transparent tags - * - * @param path The path of the request - * @param methodName HTTP method - * @param headers HTTP request headers - * @param parameters URL parameter - * @param keys Transparent transmission is marked with a key - * @return Marks for transparent transmission - */ - public abstract Map> getRequestTag(String path, String methodName, - Map> headers, Map parameters, Keys keys); - - /** - * Transparent transmission marks the key entity - * - * @author provenceee - * @since 2023-02-21 - */ - public static class Keys { - private final Set matchKeys; - - private final Set injectTags; - - /** - * Constructor - * - * @param matchKeys Label routing transparent transmission markers - * @param injectTags Swim lane transparent markers - */ - public Keys(Set matchKeys, Set injectTags) { - this.matchKeys = matchKeys; - this.injectTags = injectTags; - } - - public Set getMatchKeys() { - return matchKeys; - } - - public Set getInjectTags() { - return injectTags; - } - } -} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneMappingHandler.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneHandler.java similarity index 88% rename from sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneMappingHandler.java rename to sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneHandler.java index 1b645da086..8c3711dc88 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneMappingHandler.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2023-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import io.sermant.core.plugin.service.PluginServiceManager; import io.sermant.router.common.constants.RouterConstant; import io.sermant.router.common.utils.CollectionUtils; +import io.sermant.router.spring.entity.Keys; import io.sermant.router.spring.service.LaneService; import java.util.Collections; @@ -30,12 +31,12 @@ import java.util.logging.Logger; /** - * AbstractHandlerMapping handler + * lane handler * * @author provenceee * @since 2023-02-21 */ -public class LaneMappingHandler extends AbstractMappingHandler { +public class LaneHandler extends AbstractHandler { private static final Logger LOGGER = LoggerFactory.getLogger(); private final LaneService laneService; @@ -43,7 +44,7 @@ public class LaneMappingHandler extends AbstractMappingHandler { /** * Constructor */ - public LaneMappingHandler() { + public LaneHandler() { laneService = PluginServiceManager.getPluginService(LaneService.class); } @@ -54,12 +55,13 @@ public LaneMappingHandler() { * @param methodName http method * @param headers HTTP request headers * @param parameters URL parameter + * @param keys The key of the tag to be obtained * @return Marks for transparent transmission */ @Override public Map> getRequestTag(String path, String methodName, Map> headers, - Map> parameters) { - Set injectTags = configService.getInjectTags(); + Map> parameters, Keys keys) { + Set injectTags = keys.getInjectedTags(); if (CollectionUtils.isEmpty(injectTags)) { // The staining mark is empty, which means that there are no staining rules, and it is returned directly LOGGER.fine("Lane tags are empty."); diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneRequestTagHandler.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneRequestTagHandler.java deleted file mode 100644 index 077caef946..0000000000 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/LaneRequestTagHandler.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.sermant.router.spring.handler; - -import io.sermant.core.common.LoggerFactory; -import io.sermant.core.plugin.service.PluginServiceManager; -import io.sermant.router.common.constants.RouterConstant; -import io.sermant.router.common.utils.CollectionUtils; -import io.sermant.router.spring.service.LaneService; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Stain web blocker handler - * - * @author provenceee - * @since 2023-02-21 - */ -public class LaneRequestTagHandler extends AbstractRequestTagHandler { - private static final Logger LOGGER = LoggerFactory.getLogger(); - - private final LaneService laneService; - - /** - * Constructor - */ - public LaneRequestTagHandler() { - laneService = PluginServiceManager.getPluginService(LaneService.class); - } - - /** - * Obtain transparent tags - * - * @param path The path of the request - * @param methodName The name of the method - * @param headers HTTP request headers - * @return Marks for transparent transmission - */ - @Override - public Map> getRequestTag(String path, String methodName, Map> headers, - Map parameters, Keys keys) { - Set injectTags = keys.getInjectTags(); - if (CollectionUtils.isEmpty(injectTags)) { - // The staining mark is empty, which means that there are no staining rules, and it is returned directly - LOGGER.fine("Lane tags are empty."); - return Collections.emptyMap(); - } - - // Markers for upstream transparent transmissions - Map> tags = getRequestTag(headers, injectTags); - - // This staining marker - Map> laneTag = laneService.getLaneByParameterArray(path, methodName, headers, parameters); - if (CollectionUtils.isEmpty(laneTag)) { - LOGGER.fine("Lane is empty."); - return tags; - } - - // If there is a marker in the upstream transmission that is the same as the one in this staining, - // the upstream transmission shall prevail - laneTag.forEach(tags::putIfAbsent); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.fine("Lane is " + tags); - } - return tags; - } - - @Override - public int getOrder() { - return RouterConstant.LANE_HANDLER_ORDER; - } -} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/RouteRequestTagHandler.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/RouteRequestTagHandler.java deleted file mode 100644 index d9a5c7f50f..0000000000 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/RouteRequestTagHandler.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.sermant.router.spring.handler; - -import io.sermant.router.common.constants.RouterConstant; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Routing web interceptor handler - * - * @author provenceee - * @since 2023-02-21 - */ -public class RouteRequestTagHandler extends AbstractRequestTagHandler { - /** - * Obtain transparent tags - * - * @param path The path of the request - * @param methodName The name of the method - * @param headers HTTP request headers - * @return Marks for transparent transmission - */ - @Override - public Map> getRequestTag(String path, String methodName, Map> headers, - Map parameters, Keys keys) { - Set matchKeys = keys.getMatchKeys(); - return getRequestTag(headers, matchKeys); - } - - @Override - public int getOrder() { - return RouterConstant.ROUTER_HANDLER_ORDER; - } -} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/RouteMappingHandler.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/TagHandler.java similarity index 79% rename from sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/RouteMappingHandler.java rename to sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/TagHandler.java index e3a1b3df5c..485ab06e1e 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/RouteMappingHandler.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/handler/TagHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2023-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,18 +17,19 @@ package io.sermant.router.spring.handler; import io.sermant.router.common.constants.RouterConstant; +import io.sermant.router.spring.entity.Keys; import java.util.List; import java.util.Map; import java.util.Set; /** - * AbstractHandlerMapping handler + * tag handler * * @author provenceee * @since 2023-02-21 */ -public class RouteMappingHandler extends AbstractMappingHandler { +public class TagHandler extends AbstractHandler { /** * Obtain transparent tags * @@ -36,12 +37,13 @@ public class RouteMappingHandler extends AbstractMappingHandler { * @param methodName http method * @param headers HTTP request headers * @param parameters URL parameter + * @param keys The key of the tag to be obtained * @return Marks for transparent transmission */ @Override public Map> getRequestTag(String path, String methodName, Map> headers, - Map> parameters) { - Set matchKeys = configService.getMatchKeys(); + Map> parameters, Keys keys) { + Set matchKeys = keys.getMatchedKeys(); return getRequestTag(headers, matchKeys); } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/AbstractHandlerMappingInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/AbstractHandlerMappingInterceptor.java index 1a81fe4911..a6efaa0d6a 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/AbstractHandlerMappingInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/AbstractHandlerMappingInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,11 +18,16 @@ import io.sermant.core.plugin.agent.entity.ExecuteContext; import io.sermant.core.plugin.agent.interceptor.AbstractInterceptor; +import io.sermant.core.plugin.service.PluginServiceManager; import io.sermant.router.common.handler.Handler; +import io.sermant.router.common.utils.CollectionUtils; import io.sermant.router.common.utils.ThreadLocalUtils; -import io.sermant.router.spring.handler.AbstractMappingHandler; -import io.sermant.router.spring.handler.LaneMappingHandler; -import io.sermant.router.spring.handler.RouteMappingHandler; +import io.sermant.router.spring.entity.Keys; +import io.sermant.router.spring.handler.AbstractHandler; +import io.sermant.router.spring.handler.LaneHandler; +import io.sermant.router.spring.handler.TagHandler; +import io.sermant.router.spring.service.SpringConfigService; +import io.sermant.router.spring.utils.SpringRouterUtils; import org.springframework.http.HttpHeaders; import org.springframework.http.server.reactive.ServerHttpRequest; @@ -32,6 +37,7 @@ import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.Set; /** * Webflux obtains the header interception point @@ -43,15 +49,18 @@ public class AbstractHandlerMappingInterceptor extends AbstractInterceptor { private static final String EXCEPT_CLASS_NAME = "org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping"; - private final List handlers; + private final SpringConfigService configService; + + private final List handlers; /** * Constructor */ public AbstractHandlerMappingInterceptor() { + configService = PluginServiceManager.getPluginService(SpringConfigService.class); handlers = new ArrayList<>(); - handlers.add(new LaneMappingHandler()); - handlers.add(new RouteMappingHandler()); + handlers.add(new LaneHandler()); + handlers.add(new TagHandler()); handlers.sort(Comparator.comparingInt(Handler::getOrder)); } @@ -59,14 +68,21 @@ public AbstractHandlerMappingInterceptor() { public ExecuteContext before(ExecuteContext context) { if (shouldHandle(context)) { ThreadLocalUtils.removeRequestTag(); + Set matchKeys = configService.getMatchKeys(); + Set injectTags = configService.getInjectTags(); + if (CollectionUtils.isEmpty(matchKeys) && CollectionUtils.isEmpty(injectTags)) { + // The staining mark is empty, which means that there are no staining rules, and it is returned directly + return context; + } ServerWebExchange exchange = (ServerWebExchange) context.getArguments()[0]; ServerHttpRequest request = exchange.getRequest(); HttpHeaders headers = request.getHeaders(); String path = request.getURI().getPath(); String methodName = request.getMethod().name(); - Map> queryParams = request.getQueryParams(); - handlers.forEach(handler -> ThreadLocalUtils - .addRequestTag(handler.getRequestTag(path, methodName, headers, queryParams))); + String query = request.getURI().getQuery(); + Map> queryParams = SpringRouterUtils.getParametersByQuery(query); + handlers.forEach(handler -> ThreadLocalUtils.addRequestTag( + handler.getRequestTag(path, methodName, headers, queryParams, new Keys(matchKeys, injectTags)))); } return context; } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/DiscoveryManagerInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/DiscoveryManagerInterceptor.java index 4c92acf37b..b92aa5f46e 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/DiscoveryManagerInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/DiscoveryManagerInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,6 +59,7 @@ public ExecuteContext before(ExecuteContext context) { Object serviceName = ReflectUtils.getFieldValue(obj, "serviceName").orElse(null); if (serviceName instanceof String) { AppCache.INSTANCE.setAppName((String) serviceName); + configService.init(RouterConstant.SPRING_CACHE_NAME, (String) serviceName); } else { LOGGER.warning("Service name is null or not instanceof string."); } @@ -69,7 +70,6 @@ public ExecuteContext before(ExecuteContext context) { @Override public ExecuteContext after(ExecuteContext context) { - configService.init(RouterConstant.SPRING_CACHE_NAME, AppCache.INSTANCE.getAppName()); return context; } } \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/DispatcherServletInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/DispatcherServletInterceptor.java new file mode 100644 index 0000000000..ee7a6bcdbf --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/DispatcherServletInterceptor.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.sermant.router.spring.interceptor; + +import io.sermant.core.common.LoggerFactory; +import io.sermant.core.plugin.agent.entity.ExecuteContext; +import io.sermant.core.plugin.agent.interceptor.AbstractInterceptor; +import io.sermant.core.plugin.service.PluginServiceManager; +import io.sermant.core.utils.StringUtils; +import io.sermant.router.common.handler.Handler; +import io.sermant.router.common.utils.CollectionUtils; +import io.sermant.router.common.utils.ThreadLocalUtils; +import io.sermant.router.spring.entity.Keys; +import io.sermant.router.spring.handler.AbstractHandler; +import io.sermant.router.spring.handler.LaneHandler; +import io.sermant.router.spring.handler.TagHandler; +import io.sermant.router.spring.service.SpringConfigService; +import io.sermant.router.spring.utils.SpringRouterUtils; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.servlet.http.HttpServletRequest; + +/** + * get http request data + * + * @author provenceee + * @since 2022-07-12 + */ +public class DispatcherServletInterceptor extends AbstractInterceptor { + private static final Logger LOGGER = LoggerFactory.getLogger(); + + private final List handlers; + + private final SpringConfigService configService; + + private Function getQueryString; + + private Function getRequestUri; + + private Function getMethod; + + private Function> getHeaderNames; + + private BiFunction> getHeaders; + + /** + * Constructor + */ + public DispatcherServletInterceptor() { + configService = PluginServiceManager.getPluginService(SpringConfigService.class); + handlers = new ArrayList<>(); + handlers.add(new LaneHandler()); + handlers.add(new TagHandler()); + handlers.sort(Comparator.comparingInt(Handler::getOrder)); + initFunction(); + } + + @Override + public ExecuteContext before(ExecuteContext context) { + Set matchKeys = configService.getMatchKeys(); + Set injectTags = configService.getInjectTags(); + if (CollectionUtils.isEmpty(matchKeys) && CollectionUtils.isEmpty(injectTags)) { + // The staining mark is empty, which means that there are no staining rules, and it is returned directly + return context; + } + Object request = context.getArguments()[0]; + Map> headers = getHeaders(request); + String queryString = getQueryString.apply(request); + String decode = Optional.ofNullable(queryString).map(this::decode).orElse(StringUtils.EMPTY); + Map> queryParams = SpringRouterUtils.getParametersByQuery(decode); + String path = getRequestUri.apply(request); + String method = getMethod.apply(request); + handlers.forEach(handler -> ThreadLocalUtils.addRequestTag( + handler.getRequestTag(path, method, headers, queryParams, new Keys(matchKeys, injectTags)))); + return context; + } + + @Override + public ExecuteContext after(ExecuteContext context) { + ThreadLocalUtils.removeRequestData(); + ThreadLocalUtils.removeRequestTag(); + return context; + } + + @Override + public ExecuteContext onThrow(ExecuteContext context) { + ThreadLocalUtils.removeRequestData(); + ThreadLocalUtils.removeRequestTag(); + return context; + } + + private String decode(String str) { + try { + return URLDecoder.decode(str, StandardCharsets.UTF_8.name()); + } catch (UnsupportedEncodingException ex) { + LOGGER.log(Level.SEVERE, "Cannot decode the string[{0}], ex is {1}.", new Object[]{str, ex.getMessage()}); + return StringUtils.EMPTY; + } + } + + private Map> getHeaders(Object request) { + Map> headers = new HashMap<>(); + Enumeration enumeration = getHeaderNames.apply(request); + while (enumeration.hasMoreElements()) { + String key = (String) enumeration.nextElement(); + headers.put(key, enumeration2List(getHeaders.apply(request, key))); + } + return headers; + } + + private List enumeration2List(Enumeration enumeration) { + if (enumeration == null) { + return Collections.emptyList(); + } + List collection = new ArrayList<>(); + while (enumeration.hasMoreElements()) { + collection.add((String) enumeration.nextElement()); + } + return collection; + } + + private void initFunction() { + boolean canLoadLowVersion = canLoadLowVersion(); + if (canLoadLowVersion) { + getQueryString = obj -> ((HttpServletRequest) obj).getQueryString(); + getRequestUri = obj -> ((HttpServletRequest) obj).getRequestURI(); + getMethod = obj -> ((HttpServletRequest) obj).getMethod(); + getHeaderNames = obj -> ((HttpServletRequest) obj).getHeaderNames(); + getHeaders = (obj, key) -> ((HttpServletRequest) obj).getHeaders(key); + } else { + getQueryString = SpringRouterUtils::getQueryString; + getRequestUri = SpringRouterUtils::getRequestUri; + getMethod = SpringRouterUtils::getMethod; + getHeaderNames = SpringRouterUtils::getHeaderNames; + getHeaders = SpringRouterUtils::getHeaders; + } + } + + private boolean canLoadLowVersion() { + try { + Class.forName(HttpServletRequest.class.getCanonicalName()); + } catch (NoClassDefFoundError | ClassNotFoundException error) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/EurekaHttpClientInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/EurekaHttpClientInterceptor.java index 9bf48270e6..9c5d74a568 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/EurekaHttpClientInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/EurekaHttpClientInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,6 +53,7 @@ public ExecuteContext before(ExecuteContext context) { if (argument instanceof InstanceInfo) { InstanceInfo instanceInfo = (InstanceInfo) argument; AppCache.INSTANCE.setAppName(instanceInfo.getAppName()); + configService.init(RouterConstant.SPRING_CACHE_NAME, instanceInfo.getAppName()); SpringRouterUtils.putMetaData(instanceInfo.getMetadata(), routerConfig); } return context; @@ -60,7 +61,6 @@ public ExecuteContext before(ExecuteContext context) { @Override public ExecuteContext after(ExecuteContext context) { - configService.init(RouterConstant.SPRING_CACHE_NAME, AppCache.INSTANCE.getAppName()); return context; } } \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HandlerExecutionChainInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HandlerExecutionChainInterceptor.java deleted file mode 100644 index 181c5bc433..0000000000 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HandlerExecutionChainInterceptor.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.sermant.router.spring.interceptor; - -import io.sermant.core.plugin.agent.entity.ExecuteContext; -import io.sermant.core.plugin.agent.interceptor.AbstractInterceptor; -import io.sermant.core.utils.ClassUtils; - -import org.springframework.web.servlet.HandlerExecutionChain; -import org.springframework.web.servlet.HandlerInterceptor; - -/** - * Add an injection interceptor by intercepting and inject a spring web interceptor - * - * @author provenceee - * @since 2022-07-12 - */ -public class HandlerExecutionChainInterceptor extends AbstractInterceptor { - private static final String ROUTE_HANDLER_CLASS_NAME - = "io.sermant.router.spring.interceptor.RouteHandlerInterceptor"; - - private volatile HandlerInterceptor handlerInterceptor; - - @Override - public ExecuteContext before(ExecuteContext context) { - Object object = context.getObject(); - if (object instanceof HandlerExecutionChain) { - HandlerExecutionChain chain = (HandlerExecutionChain) object; - chain.addInterceptor(getInterceptor()); - } - return context; - } - - @Override - public ExecuteContext after(ExecuteContext context) { - return context; - } - - private HandlerInterceptor getInterceptor() { - if (handlerInterceptor == null) { - synchronized (HandlerExecutionChainInterceptor.class) { - if (handlerInterceptor == null) { - ClassUtils.defineClass(ROUTE_HANDLER_CLASS_NAME, getClass().getClassLoader()); - handlerInterceptor = new RouteHandlerInterceptor(); - } - } - } - return handlerInterceptor; - } -} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/RouteHandlerInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/RouteHandlerInterceptor.java deleted file mode 100644 index dfb1ee5d46..0000000000 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/RouteHandlerInterceptor.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.sermant.router.spring.interceptor; - -import io.sermant.core.plugin.service.PluginServiceManager; -import io.sermant.router.common.handler.Handler; -import io.sermant.router.common.utils.CollectionUtils; -import io.sermant.router.common.utils.ThreadLocalUtils; -import io.sermant.router.spring.handler.AbstractRequestTagHandler; -import io.sermant.router.spring.handler.AbstractRequestTagHandler.Keys; -import io.sermant.router.spring.handler.LaneRequestTagHandler; -import io.sermant.router.spring.handler.RouteRequestTagHandler; -import io.sermant.router.spring.service.SpringConfigService; - -import org.springframework.web.servlet.HandlerInterceptor; -import org.springframework.web.servlet.ModelAndView; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * Spring Interceptor - * - * @author provenceee - * @since 2022-07-12 - */ -public class RouteHandlerInterceptor implements HandlerInterceptor { - private final List handlers; - - private final SpringConfigService configService; - - /** - * Constructor - */ - public RouteHandlerInterceptor() { - configService = PluginServiceManager.getPluginService(SpringConfigService.class); - handlers = new ArrayList<>(); - handlers.add(new LaneRequestTagHandler()); - handlers.add(new RouteRequestTagHandler()); - handlers.sort(Comparator.comparingInt(Handler::getOrder)); - } - - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) { - Set matchKeys = configService.getMatchKeys(); - Set injectTags = configService.getInjectTags(); - if (CollectionUtils.isEmpty(matchKeys) && CollectionUtils.isEmpty(injectTags)) { - // The staining mark is empty, which means that there are no staining rules, and it is returned directly - return true; - } - Map> headers = getHeaders(request); - Map parameterMap = request.getParameterMap(); - String path = request.getRequestURI(); - String method = request.getMethod(); - handlers.forEach(handler -> ThreadLocalUtils.addRequestTag( - handler.getRequestTag(path, method, headers, parameterMap, new Keys(matchKeys, injectTags)))); - return true; - } - - @Override - public void postHandle(HttpServletRequest request, HttpServletResponse response, Object obj, - ModelAndView modelAndView) { - } - - @Override - public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object obj, Exception ex) { - ThreadLocalUtils.removeRequestTag(); - } - - private Map> getHeaders(HttpServletRequest request) { - Map> headers = new HashMap<>(); - Enumeration enumeration = request.getHeaderNames(); - while (enumeration.hasMoreElements()) { - String key = (String) enumeration.nextElement(); - headers.put(key, enumeration2List(request.getHeaders(key))); - } - return headers; - } - - private List enumeration2List(Enumeration enumeration) { - if (enumeration == null) { - return Collections.emptyList(); - } - List collection = new ArrayList<>(); - while (enumeration.hasMoreElements()) { - collection.add((String) enumeration.nextElement()); - } - return collection; - } -} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/ServiceRegistryInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/ServiceRegistryInterceptor.java index f46ca13fce..030312322c 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/ServiceRegistryInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/ServiceRegistryInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -66,6 +66,7 @@ public ExecuteContext before(ExecuteContext context) { serviceRegistration.getClass().getDeclaredMethod("getRegistration")) .invoke(serviceRegistration); AppCache.INSTANCE.setAppName(registration.getServiceId()); + configService.init(RouterConstant.SPRING_CACHE_NAME, registration.getServiceId()); SpringRouterUtils.putMetaData(registration.getMetadata(), routerConfig); } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException ex) { LOGGER.log(Level.WARNING, "Can not get the registration.", ex); @@ -76,7 +77,6 @@ public ExecuteContext before(ExecuteContext context) { @Override public ExecuteContext after(ExecuteContext context) { - configService.init(RouterConstant.SPRING_CACHE_NAME, AppCache.INSTANCE.getAppName()); return context; } } \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/service/LaneService.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/service/LaneService.java index 170318a457..e3e248a9bd 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/service/LaneService.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/service/LaneService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2023-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,18 +28,6 @@ * @since 2023-02-20 */ public interface LaneService extends PluginService { - /** - * Get swimlane markers - * - * @param path The path of the request - * @param methodName http method - * @param headers HTTP request headers - * @param parameters URL parameter - * @return Swimlane markers - */ - Map> getLaneByParameterArray(String path, String methodName, Map> headers, - Map parameters); - /** * Get swimlane markers * diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/utils/SpringRouterUtils.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/utils/SpringRouterUtils.java index b27638bb5d..f873be355a 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/utils/SpringRouterUtils.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/utils/SpringRouterUtils.java @@ -29,6 +29,9 @@ import org.springframework.cloud.client.DefaultServiceInstance; import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -45,11 +48,87 @@ public class SpringRouterUtils { private static final String ZONE_KEY = "zone"; + private static final String QUERY_SEPARATOR = "&"; + + private static final String KV_SEPARATOR = "="; + + private static final int KV_SPLIT_LENGTH = 2; + private static RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); private SpringRouterUtils() { } + /** + * get parameters from query sting + * + * @param query query sting + * @return parameters + */ + public static Map> getParametersByQuery(String query) { + if (StringUtils.isBlank(query)) { + return Collections.emptyMap(); + } + String[] queryArr = query.split(QUERY_SEPARATOR); + Map> parameters = new HashMap<>(); + for (String kv : queryArr) { + String[] kvArr = kv.split(KV_SEPARATOR, KV_SPLIT_LENGTH); + parameters.computeIfAbsent(kvArr[0], value -> new ArrayList<>()).add(kvArr[1]); + } + return Collections.unmodifiableMap(parameters); + } + + /** + * get http query + * + * @param obj HttpServletRequest + * @return query + */ + public static String getQueryString(Object obj) { + return ReflectUtils.invokeWithNoneParameterAndReturnString(obj, "getQueryString"); + } + + /** + * get http uri + * + * @param obj HttpServletRequest + * @return uri + */ + public static String getRequestUri(Object obj) { + return ReflectUtils.invokeWithNoneParameterAndReturnString(obj, "getRequestURI"); + } + + /** + * get http method + * + * @param obj HttpServletRequest + * @return method + */ + public static String getMethod(Object obj) { + return ReflectUtils.invokeWithNoneParameterAndReturnString(obj, "getMethod"); + } + + /** + * get http header keys + * + * @param obj HttpServletRequest + * @return key + */ + public static Enumeration getHeaderNames(Object obj) { + return (Enumeration) ReflectUtils.invokeWithNoneParameter(obj, "getHeaderNames"); + } + + /** + * get http header value + * + * @param obj HttpServletRequest + * @param key header key + * @return header value + */ + public static Enumeration getHeaders(Object obj, String key) { + return (Enumeration) ReflectUtils.invokeWithParameter(obj, "getHeaders", key, String.class); + } + /** * get SpringCloud ServiceInstance By XdsServiceInstance * diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/resources/META-INF/services/io.sermant.core.plugin.agent.declarer.PluginDeclarer b/sermant-plugins/sermant-router/spring-router-plugin/src/main/resources/META-INF/services/io.sermant.core.plugin.agent.declarer.PluginDeclarer index 9576a11665..5e929dba31 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/resources/META-INF/services/io.sermant.core.plugin.agent.declarer.PluginDeclarer +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/resources/META-INF/services/io.sermant.core.plugin.agent.declarer.PluginDeclarer @@ -4,7 +4,7 @@ io.sermant.router.spring.declarer.ClientHttpRequestDeclarer io.sermant.router.spring.declarer.DiscoveryManagerDeclarer io.sermant.router.spring.declarer.EurekaHttpClientDeclarer io.sermant.router.spring.declarer.FeignClientDeclarer -io.sermant.router.spring.declarer.HandlerExecutionChainDeclarer +io.sermant.router.spring.declarer.DispatcherServletDeclarer io.sermant.router.spring.declarer.HystrixActionDeclarer io.sermant.router.spring.declarer.LoadBalancerClientFilterDeclarer io.sermant.router.spring.declarer.NopInstanceFilterDeclarer diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneMappingHandlerTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneHandlerTest.java similarity index 76% rename from sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneMappingHandlerTest.java rename to sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneHandlerTest.java index 6fb9d4e6c9..c21cd5682a 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneMappingHandlerTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneHandlerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2023-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,12 @@ package io.sermant.router.spring.handler; +import io.sermant.core.plugin.config.PluginConfigManager; import io.sermant.core.service.ServiceManager; +import io.sermant.router.common.config.RouterConfig; import io.sermant.router.spring.TestSpringConfigService; +import io.sermant.router.spring.entity.Keys; import io.sermant.router.spring.service.LaneService; -import io.sermant.router.spring.service.SpringConfigService; import org.junit.AfterClass; import org.junit.Assert; @@ -39,14 +41,16 @@ * @author provenceee * @since 2023-02-28 */ -public class LaneMappingHandlerTest { +public class LaneHandlerTest { private static MockedStatic mockServiceManager; + private static MockedStatic mockPluginConfigManager; + private static TestLaneService laneService; private static TestSpringConfigService configService; - private final LaneMappingHandler handler; + private final LaneHandler handler; /** * Perform mock before the UT is executed @@ -58,8 +62,9 @@ public static void before() { mockServiceManager.when(() -> ServiceManager.getService(LaneService.class)) .thenReturn(laneService); configService = new TestSpringConfigService(); - mockServiceManager.when(() -> ServiceManager.getService(SpringConfigService.class)) - .thenReturn(configService); + mockPluginConfigManager = Mockito.mockStatic(PluginConfigManager.class); + mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(RouterConfig.class)). + thenReturn(new RouterConfig()); } /** @@ -68,10 +73,11 @@ public static void before() { @AfterClass public static void after() { mockServiceManager.close(); + mockPluginConfigManager.close(); } - public LaneMappingHandlerTest() { - handler = new LaneMappingHandler(); + public LaneHandlerTest() { + handler = new LaneHandler(); } /** @@ -81,7 +87,8 @@ public LaneMappingHandlerTest() { public void testGetRequestTag() { // Test matchTags as null configService.setReturnEmptyWhenGetMatchTags(true); - Map> requestTag = handler.getRequestTag("", "", null, null); + Map> requestTag = handler.getRequestTag("", "", null, null, + new Keys(configService.getMatchKeys(), configService.getInjectTags())); Assert.assertEquals(requestTag, Collections.emptyMap()); // Test getLane returns null @@ -90,7 +97,8 @@ public void testGetRequestTag() { Map> headers = new HashMap<>(); headers.put("bar", Collections.singletonList("bar1")); headers.put("foo", Collections.singletonList("foo1")); - requestTag = handler.getRequestTag("", "", headers, null); + requestTag = handler.getRequestTag("", "", headers, null, + new Keys(configService.getMatchKeys(), configService.getInjectTags())); Assert.assertEquals(2, requestTag.size()); Assert.assertEquals("bar1", requestTag.get("bar").get(0)); Assert.assertEquals("foo1", requestTag.get("foo").get(0)); @@ -98,10 +106,11 @@ public void testGetRequestTag() { // Test getLane is not empty configService.setReturnEmptyWhenGetMatchTags(false); laneService.setReturnEmpty(false); - requestTag = handler.getRequestTag("", "", headers, null); + requestTag = handler.getRequestTag("", "", headers, null, + new Keys(configService.getMatchKeys(), configService.getInjectTags())); Assert.assertEquals(3, requestTag.size()); Assert.assertEquals("bar1", requestTag.get("bar").get(0)); Assert.assertEquals("foo1", requestTag.get("foo").get(0)); Assert.assertEquals("flag1", requestTag.get("sermant-flag").get(0)); } -} \ No newline at end of file +} diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneRequestTagHandlerTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneRequestTagHandlerTest.java deleted file mode 100644 index 22c8933aef..0000000000 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/LaneRequestTagHandlerTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.sermant.router.spring.handler; - -import io.sermant.core.service.ServiceManager; -import io.sermant.router.spring.handler.AbstractRequestTagHandler.Keys; -import io.sermant.router.spring.service.LaneService; - -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; - -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Test LaneInterceptorHandler - * - * @author provenceee - * @since 2023-02-28 - */ -public class LaneRequestTagHandlerTest { - private static MockedStatic mockServiceManager; - - private static TestLaneService laneService; - - private final LaneRequestTagHandler handler; - - /** - * Perform mock before the UT is executed - */ - @BeforeClass - public static void before() { - mockServiceManager = Mockito.mockStatic(ServiceManager.class); - laneService = new TestLaneService(); - mockServiceManager.when(() -> ServiceManager.getService(LaneService.class)) - .thenReturn(laneService); - } - - /** - * Release the mock object after the UT is executed - */ - @AfterClass - public static void after() { - mockServiceManager.close(); - } - - public LaneRequestTagHandlerTest() { - handler = new LaneRequestTagHandler(); - } - - /** - * Test the getRequestTag method - */ - @Test - public void testGetRequestTag() { - // Test matchTags as null - Map> requestTag = handler.getRequestTag("", "", null, null, new Keys(null, null)); - Assert.assertEquals(requestTag, Collections.emptyMap()); - - // Test getLane returns null - laneService.setReturnEmpty(true); - Map> headers = new HashMap<>(); - headers.put("bar", Collections.singletonList("bar1")); - headers.put("foo", Collections.singletonList("foo1")); - Set matchTags = new HashSet<>(); - matchTags.add("bar"); - matchTags.add("foo"); - requestTag = handler.getRequestTag("", "", headers, null, new Keys(null, matchTags)); - Assert.assertEquals(2, requestTag.size()); - Assert.assertEquals("bar1", requestTag.get("bar").get(0)); - Assert.assertEquals("foo1", requestTag.get("foo").get(0)); - - // Test getLane is not empty - laneService.setReturnEmpty(false); - requestTag = handler.getRequestTag("", "", headers, null, new Keys(null, matchTags)); - Assert.assertEquals(3, requestTag.size()); - Assert.assertEquals("bar1", requestTag.get("bar").get(0)); - Assert.assertEquals("foo1", requestTag.get("foo").get(0)); - Assert.assertEquals("flag1", requestTag.get("sermant-flag").get(0)); - } -} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/RouteRequestTagHandlerTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/RouteRequestTagHandlerTest.java deleted file mode 100644 index ca9f8614cd..0000000000 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/RouteRequestTagHandlerTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.sermant.router.spring.handler; - -import io.sermant.router.spring.handler.AbstractRequestTagHandler.Keys; - -import org.junit.Assert; -import org.junit.Test; - -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Test RouteInterceptorHandler - * - * @author provenceee - * @since 2023-02-28 - */ -public class RouteRequestTagHandlerTest { - private final RouteRequestTagHandler handler; - - public RouteRequestTagHandlerTest() { - handler = new RouteRequestTagHandler(); - } - - /** - * Test the getRequestTag method - */ - @Test - public void testGetRequestTag() { - // Normal - Map> headers = new HashMap<>(); - Set matchKeys = new HashSet<>(); - matchKeys.add("bar"); - matchKeys.add("foo"); - headers.put("bar", Collections.singletonList("bar1")); - headers.put("foo", Collections.singletonList("foo1")); - Map> requestTag = handler.getRequestTag("", "", headers, null, new Keys(matchKeys, null)); - Assert.assertNotNull(requestTag); - Assert.assertEquals(2, requestTag.size()); - Assert.assertEquals("bar1", requestTag.get("bar").get(0)); - Assert.assertEquals("foo1", requestTag.get("foo").get(0)); - - // Test matchKeys as empty - requestTag = handler.getRequestTag("", "", null, null, new Keys(null, null)); - Assert.assertEquals(Collections.emptyMap(), requestTag); - } -} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/RouteMappingHandlerTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/TagHandlerTest.java similarity index 82% rename from sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/RouteMappingHandlerTest.java rename to sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/TagHandlerTest.java index eee68f9108..9212c238d8 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/RouteMappingHandlerTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/TagHandlerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2023-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ import io.sermant.core.service.ServiceManager; import io.sermant.router.spring.TestSpringConfigService; -import io.sermant.router.spring.service.SpringConfigService; +import io.sermant.router.spring.entity.Keys; import org.junit.AfterClass; import org.junit.Assert; @@ -38,12 +38,12 @@ * @author provenceee * @since 2023-02-28 */ -public class RouteMappingHandlerTest { +public class TagHandlerTest { private static MockedStatic mockServiceManager; private static TestSpringConfigService configService; - private final RouteMappingHandler handler; + private final TagHandler handler; /** * Perform mock before the UT is executed @@ -52,8 +52,6 @@ public class RouteMappingHandlerTest { public static void before() { mockServiceManager = Mockito.mockStatic(ServiceManager.class); configService = new TestSpringConfigService(); - mockServiceManager.when(() -> ServiceManager.getService(SpringConfigService.class)) - .thenReturn(configService); } /** @@ -64,8 +62,8 @@ public static void after() { mockServiceManager.close(); } - public RouteMappingHandlerTest() { - handler = new RouteMappingHandler(); + public TagHandlerTest() { + handler = new TagHandler(); } /** @@ -78,7 +76,8 @@ public void testGetRequestTag() { Map> headers = new HashMap<>(); headers.put("bar", Collections.singletonList("bar1")); headers.put("foo", Collections.singletonList("foo1")); - Map> requestTag = handler.getRequestTag("", "", headers, null); + Map> requestTag = handler.getRequestTag("", "", headers, null, + new Keys(configService.getMatchKeys(), configService.getInjectTags())); Assert.assertNotNull(requestTag); Assert.assertEquals(2, requestTag.size()); Assert.assertEquals("bar1", requestTag.get("bar").get(0)); @@ -86,7 +85,8 @@ public void testGetRequestTag() { // Test getMatchKeys returns null configService.setReturnEmptyWhenGetMatchKeys(true); - requestTag = handler.getRequestTag("", "", null, null); + requestTag = handler.getRequestTag("", "", null, null, + new Keys(configService.getMatchKeys(), configService.getInjectTags())); Assert.assertEquals(Collections.emptyMap(), requestTag); } } \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/TestLaneService.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/TestLaneService.java index 563471836f..576846b0f3 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/TestLaneService.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/handler/TestLaneService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2023-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,12 +32,6 @@ public class TestLaneService implements LaneService { private boolean returnEmpty; - @Override - public Map> getLaneByParameterArray(String path, String methodName, - Map> headers, Map parameters) { - return getLane(); - } - @Override public Map> getLaneByParameterList(String path, String methodName, Map> headers, Map> parameters) { diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/DiscoveryManagerInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/DiscoveryManagerInterceptorTest.java index ff3473c5c3..0f50bceac9 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/DiscoveryManagerInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/DiscoveryManagerInterceptorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -104,15 +104,6 @@ public void testBefore() { context.getArguments()[0] = new TestObject(null); interceptor.before(context); Assert.assertEquals("foo", AppCache.INSTANCE.getAppName()); - } - - /** - * Test the after method - */ - @Test - public void testAfter() { - AppCache.INSTANCE.setAppName("foo"); - interceptor.after(context); Assert.assertEquals(RouterConstant.SPRING_CACHE_NAME, configService.getCacheName()); Assert.assertEquals("foo", configService.getServiceName()); } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/RouteHandlerInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/DispatcherServletInterceptorTest.java similarity index 63% rename from sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/RouteHandlerInterceptorTest.java rename to sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/DispatcherServletInterceptorTest.java index 433cd1c427..3e54a78879 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/RouteHandlerInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/DispatcherServletInterceptorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,9 @@ package io.sermant.router.spring.interceptor; +import io.sermant.core.plugin.agent.entity.ExecuteContext; import io.sermant.core.service.ServiceManager; +import io.sermant.router.common.request.RequestData; import io.sermant.router.common.request.RequestTag; import io.sermant.router.common.utils.ThreadLocalUtils; import io.sermant.router.spring.BaseTransmitConfigTest; @@ -31,25 +33,28 @@ import org.mockito.MockedStatic; import org.mockito.Mockito; import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; import java.util.Collections; import java.util.List; import java.util.Map; /** - * Test RouteHandlerInterceptor + * Test DispatcherServletInterceptor * * @author provenceee * @since 2022-09-07 */ -public class RouteHandlerInterceptorTest extends BaseTransmitConfigTest { - private final RouteHandlerInterceptor interceptor; +public class DispatcherServletInterceptorTest extends BaseTransmitConfigTest { + private final DispatcherServletInterceptor interceptor; private static TestSpringConfigService configService; private static MockedStatic mockServiceManager; + private final ExecuteContext context; + + private final MockHttpServletRequest request; + /** * Perform mock before the UT is executed */ @@ -69,8 +74,12 @@ public static void after() { mockServiceManager.close(); } - public RouteHandlerInterceptorTest() { - interceptor = new RouteHandlerInterceptor(); + public DispatcherServletInterceptorTest() throws NoSuchMethodException { + interceptor = new DispatcherServletInterceptor(); + request = new MockHttpServletRequest(); + Object[] arguments = new Object[]{request}; + context = ExecuteContext.forMemberMethod(new Object(), String.class.getMethod("trim"), arguments, null, + null); } /** @@ -83,27 +92,24 @@ public void clear() { } /** - * Test the preHandle method + * Test the before method */ @Test - public void testPreHandle() { - MockHttpServletRequest request = new MockHttpServletRequest(); + public void testBefore() { request.addHeader("bar", "bar1"); request.addHeader("foo", "foo1"); request.addHeader("foo2", "foo2"); - MockHttpServletResponse response = new MockHttpServletResponse(); - Object obj = new Object(); // The test keys are all empty configService.setReturnEmptyWhenGetMatchTags(true); configService.setReturnEmptyWhenGetMatchKeys(true); - interceptor.preHandle(request, response, obj); + interceptor.before(context); Assert.assertNull(ThreadLocalUtils.getRequestTag()); // Test the preHandle method, getMatchKeys is not empty configService.setReturnEmptyWhenGetMatchTags(true); configService.setReturnEmptyWhenGetMatchKeys(false); - interceptor.preHandle(request, response, obj); + interceptor.before(context); RequestTag requestTag = ThreadLocalUtils.getRequestTag(); Map> header = requestTag.getTag(); Assert.assertNotNull(header); @@ -113,15 +119,32 @@ public void testPreHandle() { } /** - * After testing is completed, verify if the thread variables are released + * Test the after method, verify if the thread variables are released + */ + @Test + public void testAfter() { + ThreadLocalUtils.addRequestTag(Collections.singletonMap("bar", Collections.singletonList("foo"))); + ThreadLocalUtils.setRequestData(new RequestData(Collections.emptyMap(), "", "")); + Assert.assertNotNull(ThreadLocalUtils.getRequestTag()); + + // Test the after method, verify if thread variables are released + interceptor.after(context); + Assert.assertNull(ThreadLocalUtils.getRequestTag()); + Assert.assertNull(ThreadLocalUtils.getRequestData()); + } + + /** + * Test the onThrow method, verify if the thread variables are released */ @Test - public void testAfterCompletion() { + public void testOnThrow() { ThreadLocalUtils.addRequestTag(Collections.singletonMap("bar", Collections.singletonList("foo"))); + ThreadLocalUtils.setRequestData(new RequestData(Collections.emptyMap(), "", "")); Assert.assertNotNull(ThreadLocalUtils.getRequestTag()); - // Test afterCompletion to verify if thread variables are released - interceptor.afterCompletion(new MockHttpServletRequest(), new MockHttpServletResponse(), new Object(), null); + // Test the onThrow method, verify if thread variables are released + interceptor.onThrow(context); Assert.assertNull(ThreadLocalUtils.getRequestTag()); + Assert.assertNull(ThreadLocalUtils.getRequestData()); } } \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/EurekaHttpClientInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/EurekaHttpClientInterceptorTest.java index 782bf8afb5..33977c3d64 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/EurekaHttpClientInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/EurekaHttpClientInterceptorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -111,13 +111,6 @@ public void testBefore() { Assert.assertEquals(routerConfig.getRouterVersion(), metadata.get("version")); Assert.assertEquals("bar1", metadata.get("bar")); Assert.assertEquals("foo2", metadata.get("foo")); - } - - /** - * Test the after method - */ - @Test - public void testAfter() { AppCache.INSTANCE.setAppName("FOO"); interceptor.after(context); Assert.assertEquals(RouterConstant.SPRING_CACHE_NAME, configService.getCacheName()); diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/HandlerExecutionChainInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/HandlerExecutionChainInterceptorTest.java deleted file mode 100644 index 12d3f17d3f..0000000000 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/HandlerExecutionChainInterceptorTest.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.sermant.router.spring.interceptor; - -import io.sermant.core.plugin.agent.entity.ExecuteContext; -import io.sermant.core.service.ServiceManager; -import io.sermant.router.spring.service.SpringConfigService; - -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import org.springframework.web.servlet.HandlerExecutionChain; - -import java.util.Collections; -import java.util.Set; - -/** - * Test HandlerExecutionChainInterceptor - * - * @author provenceee - * @since 2022-09-07 - */ -public class HandlerExecutionChainInterceptorTest { - private final HandlerExecutionChainInterceptor interceptor; - - private final ExecuteContext context; - - private static MockedStatic mockServiceManager; - - /** - * Perform mock before the UT is executed - */ - @BeforeClass - public static void before() { - mockServiceManager = Mockito.mockStatic(ServiceManager.class); - mockServiceManager.when(() -> ServiceManager.getService(SpringConfigService.class)).thenReturn( - new SpringConfigService() { - @Override - public void init(String cacheName, String serviceName) { - } - - @Override - public Set getMatchKeys() { - return Collections.emptySet(); - } - - @Override - public Set getInjectTags() { - return Collections.emptySet(); - } - }); - } - - /** - * Release the mock object after the UT is executed - */ - @AfterClass - public static void after() { - mockServiceManager.close(); - } - - public HandlerExecutionChainInterceptorTest() { - interceptor = new HandlerExecutionChainInterceptor(); - context = ExecuteContext.forMemberMethod(new HandlerExecutionChain(new Object()), null, null, null, null); - } - - /** - * Test the before method - */ - @Test - public void testBefore() { - interceptor.before(context); - HandlerExecutionChain chain = (HandlerExecutionChain) context.getObject(); - Assert.assertNotNull(chain.getInterceptors()); - Assert.assertEquals(1, chain.getInterceptors().length); - Assert.assertEquals(RouteHandlerInterceptor.class, chain.getInterceptors()[0].getClass()); - } -} \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/ServiceRegistryInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/ServiceRegistryInterceptorTest.java index d99a704fcf..88ec2fc54d 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/ServiceRegistryInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/ServiceRegistryInterceptorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -105,13 +105,6 @@ public void testBefore() { Assert.assertEquals(routerConfig.getRouterVersion(), metadata.get("version")); Assert.assertEquals("bar1", metadata.get("bar")); Assert.assertEquals("foo2", metadata.get("foo")); - } - - /** - * Test the after method - */ - @Test - public void testAfter() { AppCache.INSTANCE.setAppName("foo"); interceptor.after(context); Assert.assertEquals(RouterConstant.SPRING_CACHE_NAME, configService.getCacheName()); diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/utils/SpringRouterUtilsTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/utils/SpringRouterUtilsTest.java new file mode 100644 index 0000000000..eef39d3d2c --- /dev/null +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/utils/SpringRouterUtilsTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024-2024 Huawei Technologies Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.sermant.router.spring.utils; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * SpringRouterUtils test + * + * @author provenceee + * @since 2024-11-20 + */ +public class SpringRouterUtilsTest { + /** + * test getParametersByQuery + */ + @Test + public void testGetParametersByQuery() { + String query = "a=b"; + Map> parametersByQuery = SpringRouterUtils.getParametersByQuery(query); + List list = parametersByQuery.get("a"); + Assert.assertEquals(1, list.size()); + Assert.assertEquals("b", list.get(0)); + + query = "a=b&a=c"; + parametersByQuery = SpringRouterUtils.getParametersByQuery(query); + list = parametersByQuery.get("a"); + Assert.assertEquals(2, list.size()); + Assert.assertEquals("b", list.get(0)); + Assert.assertEquals("c", list.get(1)); + + query = "a=b&b=&a=c"; + parametersByQuery = SpringRouterUtils.getParametersByQuery(query); + list = parametersByQuery.get("a"); + Assert.assertEquals(2, list.size()); + Assert.assertEquals("b", list.get(0)); + Assert.assertEquals("c", list.get(1)); + list = parametersByQuery.get("b"); + Assert.assertEquals(1, list.size()); + Assert.assertEquals("", list.get(0)); + + Assert.assertEquals(Collections.emptyMap(), SpringRouterUtils.getParametersByQuery(null)); + } +} diff --git a/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/service/LaneServiceImpl.java b/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/service/LaneServiceImpl.java index 98f4e5d5e9..76c7d29dcc 100644 --- a/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/service/LaneServiceImpl.java +++ b/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/service/LaneServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2023-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,14 +37,6 @@ * @since 2023-02-20 */ public class LaneServiceImpl implements LaneService { - @Override - public Map> getLaneByParameterArray(String path, String methodName, - Map> headers, Map parameters) { - List rules = getRules(path, methodName); - List routes = RouteUtils.getLaneRoutesByParameterArray(rules, headers, parameters); - return RuleUtils.getTargetLaneTags(routes); - } - @Override public Map> getLaneByParameterList(String path, String methodName, Map> headers, Map> parameters) { diff --git a/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/utils/RouteUtils.java b/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/utils/RouteUtils.java index a038ea827d..11a41fa696 100644 --- a/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/utils/RouteUtils.java +++ b/sermant-plugins/sermant-router/spring-router-service/src/main/java/io/sermant/router/spring/utils/RouteUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2021-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,29 +39,6 @@ public class RouteUtils { private RouteUtils() { } - /** - * Get matching swimlanes - * - * @param list Valid rules - * @param headers header - * @param parameters parameters - * @return Matching swimlane markers - */ - public static List getLaneRoutesByParameterArray(List list, Map> headers, - Map parameters) { - for (Rule rule : list) { - Match match = rule.getMatch(); - if (match == null) { - return rule.getRoute(); - } - if (isMatchByHeaders(match.getHeaders(), headers) && isMatchByParameterArray(match.getParameters(), - parameters)) { - return rule.getRoute(); - } - } - return Collections.emptyList(); - } - /** * Get matching swimlanes * @@ -108,29 +85,6 @@ private static boolean isMatchByHeaders(Map> matchHeader return true; } - private static boolean isMatchByParameterArray(Map> matchParameters, - Map parameters) { - if (CollectionUtils.isEmpty(matchParameters)) { - return true; - } - for (Entry> entry : matchParameters.entrySet()) { - String key = entry.getKey(); - List matchRuleList = entry.getValue(); - for (MatchRule matchRule : matchRuleList) { - ValueMatch valueMatch = matchRule.getValueMatch(); - List values = valueMatch.getValues(); - MatchStrategy matchStrategy = valueMatch.getMatchStrategy(); - String[] arr = parameters.get(key); - String arg = (arr == null || arr.length == 0) ? null : arr[0]; - if (!matchStrategy.isMatch(values, arg, matchRule.isCaseInsensitive())) { - // As long as one of them doesn't match, it's a mismatch - return false; - } - } - } - return true; - } - private static boolean isMatchByParameterList(Map> matchParameters, Map> parameters) { if (CollectionUtils.isEmpty(matchParameters)) { diff --git a/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/service/LaneServiceTest.java b/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/service/LaneServiceTest.java index ab3b4e1adc..12c9c53bf7 100644 --- a/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/service/LaneServiceTest.java +++ b/sermant-plugins/sermant-router/spring-router-service/src/test/java/io/sermant/router/spring/service/LaneServiceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2023-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,10 +63,7 @@ public void clear() { */ @Test public void testWithInvalidConfiguration() { - Map> lane = service.getLaneByParameterArray("", "", Collections.emptyMap(), null); - Assert.assertEquals(Collections.emptyMap(), lane); - - lane = service.getLaneByParameterList("", "", Collections.emptyMap(), null); + Map> lane = service.getLaneByParameterList("", "", Collections.emptyMap(), null); Assert.assertEquals(Collections.emptyMap(), lane); } @@ -76,10 +73,7 @@ public void testWithInvalidConfiguration() { @Test public void testWithEmptyRules() { initRules(); - Map> lane = service.getLaneByParameterArray("", "", Collections.emptyMap(), null); - Assert.assertEquals(Collections.emptyMap(), lane); - - lane = service.getLaneByParameterList("", "", Collections.emptyMap(), null); + Map> lane = service.getLaneByParameterList("", "", Collections.emptyMap(), null); Assert.assertEquals(Collections.emptyMap(), lane); } @@ -90,10 +84,6 @@ public void testWithEmptyRules() { public void testWithEmptyRoutes() { initRules(); Map> lane = service - .getLaneByParameterArray("/foo/test", "get", Collections.emptyMap(), null); - Assert.assertEquals(Collections.emptyMap(), lane); - - lane = service .getLaneByParameterList("/foo/test", "get", Collections.emptyMap(), null); Assert.assertEquals(Collections.emptyMap(), lane); } @@ -105,13 +95,6 @@ public void testWithEmptyRoutes() { public void testGetLane() { initRules(); Map> lane = service - .getLaneByParameterArray("/foo/test", "get", - Collections.singletonMap("bar", Collections.singletonList("bar1")), - Collections.singletonMap("foo", new String[]{"foo1"})); - Assert.assertEquals(1, lane.size()); - Assert.assertEquals("flag1", lane.get("sermant-flag").get(0)); - - lane = service .getLaneByParameterList("/foo/test", "get", Collections.singletonMap("bar", Collections.singletonList("bar1")), Collections.singletonMap("foo", Collections.singletonList("foo1"))); diff --git a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/grace/declarers/SpringWebHandlerDeclarer.java b/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/grace/declarers/DispatcherServletDeclarer.java similarity index 76% rename from sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/grace/declarers/SpringWebHandlerDeclarer.java rename to sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/grace/declarers/DispatcherServletDeclarer.java index 9ea6785093..ad7d9d8bb0 100644 --- a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/grace/declarers/SpringWebHandlerDeclarer.java +++ b/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/grace/declarers/DispatcherServletDeclarer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import io.sermant.core.plugin.agent.declarer.InterceptDeclarer; import io.sermant.core.plugin.agent.matcher.ClassMatcher; import io.sermant.core.plugin.agent.matcher.MethodMatcher; -import io.sermant.registry.grace.interceptors.SpringWebHandlerInterceptor; +import io.sermant.registry.grace.interceptors.DispatcherServletInterceptor; /** * Inject interceptors by intercepting them @@ -29,16 +29,16 @@ * @author zhouss * @since 2022-05-23 */ -public class SpringWebHandlerDeclarer extends AbstractPluginDeclarer { +public class DispatcherServletDeclarer extends AbstractPluginDeclarer { /** * The fully qualified name of the enhanced class */ - private static final String ENHANCE_CLASS = "org.springframework.web.servlet.HandlerExecutionChain"; + private static final String ENHANCE_CLASS = "org.springframework.web.servlet.DispatcherServlet"; /** * The fully qualified name of the interception class */ - private static final String INTERCEPT_CLASS = SpringWebHandlerInterceptor.class.getCanonicalName(); + private static final String INTERCEPT_CLASS = DispatcherServletInterceptor.class.getCanonicalName(); @Override public ClassMatcher getClassMatcher() { @@ -48,7 +48,7 @@ public ClassMatcher getClassMatcher() { @Override public InterceptDeclarer[] getInterceptDeclarers(ClassLoader classLoader) { return new InterceptDeclarer[]{ - InterceptDeclarer.build(MethodMatcher.nameEquals("applyPreHandle"), INTERCEPT_CLASS) + InterceptDeclarer.build(MethodMatcher.nameEquals("doService"), INTERCEPT_CLASS) }; } } diff --git a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/grace/interceptors/DispatcherServletInterceptor.java b/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/grace/interceptors/DispatcherServletInterceptor.java new file mode 100644 index 0000000000..fffb1e68e6 --- /dev/null +++ b/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/grace/interceptors/DispatcherServletInterceptor.java @@ -0,0 +1,178 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Based on org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java + * from the Apache Dubbo project. + */ + +package io.sermant.registry.grace.interceptors; + +import io.sermant.core.plugin.agent.entity.ExecuteContext; +import io.sermant.core.plugin.config.PluginConfigManager; +import io.sermant.core.plugin.service.PluginServiceManager; +import io.sermant.core.utils.ReflectUtils; +import io.sermant.core.utils.StringUtils; +import io.sermant.registry.config.GraceConfig; +import io.sermant.registry.config.grace.GraceConstants; +import io.sermant.registry.config.grace.GraceContext; +import io.sermant.registry.config.grace.GraceShutDownManager; +import io.sermant.registry.context.RegisterContext; +import io.sermant.registry.context.RegisterContext.ClientInfo; +import io.sermant.registry.services.GraceService; + +import java.util.function.BiFunction; +import java.util.function.Function; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Spring Web request interceptors + * + * @author zhouss + * @since 2022-05-23 + */ +public class DispatcherServletInterceptor extends GraceSwitchInterceptor { + private final GraceService graceService; + + private final GraceConfig graceConfig; + + private Consumer addHeader; + + private Function getServerPort; + + private Function getRemoteAddr; + + private BiFunction getHeader; + + /** + * Constructor + */ + public DispatcherServletInterceptor() { + graceService = PluginServiceManager.getPluginService(GraceService.class); + graceConfig = PluginConfigManager.getPluginConfig(GraceConfig.class); + initFunction(); + } + + @Override + public ExecuteContext doBefore(ExecuteContext context) { + if (GraceContext.INSTANCE.getStartWarmUpTime() == 0) { + GraceContext.INSTANCE.setStartWarmUpTime(System.currentTimeMillis()); + } + Object[] arguments = context.getArguments(); + Object request = arguments[0]; + Object response = arguments[1]; + addGraceAddress(request); + final GraceShutDownManager graceShutDownManager = GraceContext.INSTANCE.getGraceShutDownManager(); + graceShutDownManager.increaseRequestCount(); + if (graceShutDownManager.isShutDown() && graceConfig.isEnableGraceShutdown()) { + // It has been marked as closed, and the number of incoming requests has been counted + final ClientInfo clientInfo = RegisterContext.INSTANCE.getClientInfo(); + addHeader.accept(response, GraceConstants.MARK_SHUTDOWN_SERVICE_ENDPOINT, + buildEndpoint(clientInfo.getIp(), clientInfo.getPort())); + addHeader.accept(response, GraceConstants.MARK_SHUTDOWN_SERVICE_ENDPOINT, + buildEndpoint(clientInfo.getHost(), clientInfo.getPort())); + addHeader.accept(response, GraceConstants.MARK_SHUTDOWN_SERVICE_NAME, clientInfo.getServiceName()); + } + return context; + } + + @Override + public ExecuteContext doAfter(ExecuteContext context) { + GraceContext.INSTANCE.getGraceShutDownManager().decreaseRequestCount(); + return context; + } + + @Override + public ExecuteContext doThrow(ExecuteContext context) { + GraceContext.INSTANCE.getGraceShutDownManager().decreaseRequestCount(); + return context; + } + + private void addGraceAddress(Object request) { + if (graceConfig.isEnableSpring() && graceConfig.isEnableGraceShutdown() && graceConfig.isEnableOfflineNotify() + && GraceConstants.GRACE_OFFLINE_SOURCE_VALUE + .equals(getHeader.apply(request, GraceConstants.GRACE_OFFLINE_SOURCE_KEY))) { + String address = getHeader.apply(request, GraceConstants.SERMANT_GRACE_ADDRESS); + if (StringUtils.isBlank(address)) { + address = getRemoteAddr.apply(request) + ":" + getServerPort.apply(request); + } + graceService.addAddress(address); + } + } + + private void addHeader(Object httpServletResponse, String key, String value) { + ReflectUtils.invokeMethod(httpServletResponse, "addHeader", new Class[]{String.class, String.class}, + new Object[]{key, value}); + } + + private int getServerPort(Object httpServletRequest) { + return (int) ReflectUtils.invokeMethodWithNoneParameter(httpServletRequest, "getServerPort").orElse(0); + } + + private String getRemoteAddr(Object httpServletRequest) { + return getString(httpServletRequest, "getRemoteAddr"); + } + + private String getHeader(Object httpServletRequest, String key) { + return (String) ReflectUtils.invokeMethod(httpServletRequest, "getHeader", new Class[]{String.class}, + new Object[]{key}).orElse(null); + } + + private String getString(Object object, String method) { + return (String) ReflectUtils.invokeMethodWithNoneParameter(object, method).orElse(null); + } + + private void initFunction() { + boolean canLoadLowVersion = canLoadLowVersion(); + if (canLoadLowVersion) { + addHeader = (obj, key, value) -> ((HttpServletResponse) obj).addHeader(key, value); + getServerPort = obj -> ((HttpServletRequest) obj).getServerPort(); + getRemoteAddr = obj -> ((HttpServletRequest) obj).getRemoteAddr(); + getHeader = (obj, key) -> ((HttpServletRequest) obj).getHeader(key); + } else { + addHeader = this::addHeader; + getServerPort = this::getServerPort; + getRemoteAddr = this::getRemoteAddr; + getHeader = this::getHeader; + } + } + + private boolean canLoadLowVersion() { + try { + Class.forName(HttpServletRequest.class.getCanonicalName()); + } catch (NoClassDefFoundError | ClassNotFoundException error) { + return false; + } + return true; + } + + /** + * mapping + * + * @param parameter1 + * @param parameter2 + * @param parameter3 + * @author proveceee + * @since 2024-11-15 + */ + @FunctionalInterface + private interface Consumer { + void accept(T t, R r, U u); + } +} diff --git a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/grace/interceptors/GraceSwitchInterceptor.java b/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/grace/interceptors/GraceSwitchInterceptor.java index 20e89021c7..11ebc67c6a 100644 --- a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/grace/interceptors/GraceSwitchInterceptor.java +++ b/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/grace/interceptors/GraceSwitchInterceptor.java @@ -74,7 +74,7 @@ protected boolean isEnabled() { * @return endpoint */ protected String buildEndpoint(String host, int port) { - return String.format(Locale.ENGLISH, "%s:%s", host, port); + return host + ":" + port; } /** diff --git a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/grace/interceptors/SpringWebHandlerInterceptor.java b/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/grace/interceptors/SpringWebHandlerInterceptor.java deleted file mode 100644 index d264a995c9..0000000000 --- a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/grace/interceptors/SpringWebHandlerInterceptor.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package io.sermant.registry.grace.interceptors; - -import io.sermant.core.plugin.agent.entity.ExecuteContext; -import io.sermant.registry.inject.grace.SpringRequestInterceptor; - -import org.springframework.web.servlet.HandlerExecutionChain; -import org.springframework.web.servlet.HandlerInterceptor; - -/** - * Inject the request interceptor - * - * @author zhouss - * @since 2022-05-23 - */ -public class SpringWebHandlerInterceptor extends GraceSwitchInterceptor { - private HandlerInterceptor handlerInterceptor; - - @Override - protected ExecuteContext doBefore(ExecuteContext context) { - final Object object = context.getObject(); - if (object instanceof HandlerExecutionChain) { - HandlerExecutionChain chain = (HandlerExecutionChain) object; - chain.addInterceptor(getInterceptor()); - } - return context; - } - - private HandlerInterceptor getInterceptor() { - if (handlerInterceptor == null) { - handlerInterceptor = new SpringRequestInterceptor(); - } - return handlerInterceptor; - } -} diff --git a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/inject/grace/SpringRequestInterceptor.java b/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/inject/grace/SpringRequestInterceptor.java deleted file mode 100644 index 401174a268..0000000000 --- a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/io/sermant/registry/inject/grace/SpringRequestInterceptor.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Based on org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java - * from the Apache Dubbo project. - */ - -package io.sermant.registry.inject.grace; - -import io.sermant.core.plugin.config.PluginConfigManager; -import io.sermant.core.plugin.service.PluginServiceManager; -import io.sermant.core.utils.StringUtils; -import io.sermant.registry.config.GraceConfig; -import io.sermant.registry.config.grace.GraceConstants; -import io.sermant.registry.config.grace.GraceContext; -import io.sermant.registry.config.grace.GraceShutDownManager; -import io.sermant.registry.context.RegisterContext; -import io.sermant.registry.context.RegisterContext.ClientInfo; -import io.sermant.registry.grace.interceptors.SpringWebHandlerInterceptor; -import io.sermant.registry.services.GraceService; - -import org.springframework.web.servlet.HandlerInterceptor; -import org.springframework.web.servlet.ModelAndView; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * Spring Web request pre-interceptors, dynamically joined by interceptors, are added with each request, - * {@link SpringWebHandlerInterceptor} - * - * @author zhouss - * @since 2022-05-23 - */ -public class SpringRequestInterceptor implements HandlerInterceptor { - private final GraceService graceService; - - private final GraceConfig graceConfig; - - /** - * Constructor - */ - public SpringRequestInterceptor() { - graceService = PluginServiceManager.getPluginService(GraceService.class); - graceConfig = PluginConfigManager.getPluginConfig(GraceConfig.class); - } - - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { - if (GraceContext.INSTANCE.getStartWarmUpTime() == 0) { - GraceContext.INSTANCE.setStartWarmUpTime(System.currentTimeMillis()); - } - addGraceAddress(request); - final GraceShutDownManager graceShutDownManager = GraceContext.INSTANCE.getGraceShutDownManager(); - graceShutDownManager.increaseRequestCount(); - if (graceShutDownManager.isShutDown() && graceConfig.isEnableGraceShutdown()) { - // It has been marked as closed, and the number of incoming requests has been counted - final ClientInfo clientInfo = RegisterContext.INSTANCE.getClientInfo(); - response.addHeader(GraceConstants.MARK_SHUTDOWN_SERVICE_ENDPOINT, - buildEndpoint(clientInfo.getIp(), clientInfo.getPort())); - response.addHeader(GraceConstants.MARK_SHUTDOWN_SERVICE_ENDPOINT, - buildEndpoint(clientInfo.getHost(), clientInfo.getPort())); - response.addHeader(GraceConstants.MARK_SHUTDOWN_SERVICE_NAME, clientInfo.getServiceName()); - } - return true; - } - - @Override - public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, - ModelAndView modelAndView) { - } - - @Override - public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, - Exception ex) { - GraceContext.INSTANCE.getGraceShutDownManager().decreaseRequestCount(); - } - - private String buildEndpoint(String host, int port) { - return host + ":" + port; - } - - private void addGraceAddress(HttpServletRequest request) { - if (graceConfig.isEnableSpring() && graceConfig.isEnableGraceShutdown() && graceConfig.isEnableOfflineNotify() - && GraceConstants.GRACE_OFFLINE_SOURCE_VALUE - .equals(request.getHeader(GraceConstants.GRACE_OFFLINE_SOURCE_KEY))) { - String address = request.getHeader(GraceConstants.SERMANT_GRACE_ADDRESS); - if (StringUtils.isBlank(address)) { - address = request.getRemoteAddr() + ":" + request.getServerPort(); - } - graceService.addAddress(address); - } - } -} diff --git a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/resources/META-INF/services/io.sermant.core.plugin.agent.declarer.PluginDeclarer b/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/resources/META-INF/services/io.sermant.core.plugin.agent.declarer.PluginDeclarer index d7af3eef33..e840f439d4 100644 --- a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/resources/META-INF/services/io.sermant.core.plugin.agent.declarer.PluginDeclarer +++ b/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/resources/META-INF/services/io.sermant.core.plugin.agent.declarer.PluginDeclarer @@ -1,5 +1,5 @@ # -# Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. +# Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -36,7 +36,7 @@ io.sermant.registry.declarers.health.HealthIndicatorDeclarer io.sermant.registry.grace.declarers.RegistryDelayDeclarer io.sermant.registry.grace.declarers.SpringRibbonWarmUpDeclarer io.sermant.registry.grace.declarers.SpringLoadbalancerWarmUpDeclarer -io.sermant.registry.grace.declarers.SpringWebHandlerDeclarer +io.sermant.registry.grace.declarers.DispatcherServletDeclarer io.sermant.registry.grace.declarers.SpringRibbonBalancerDeclarer io.sermant.registry.grace.declarers.SpringCacheManagerDeclarer io.sermant.registry.grace.declarers.SpringLoadbalancerFeignResponseDeclarer diff --git a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/test/java/io/sermant/registry/inject/grace/SpringRequestInterceptorTest.java b/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/test/java/io/sermant/registry/grace/interceptors/DispatcherServletInterceptorTest.java similarity index 81% rename from sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/test/java/io/sermant/registry/inject/grace/SpringRequestInterceptorTest.java rename to sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/test/java/io/sermant/registry/grace/interceptors/DispatcherServletInterceptorTest.java index c082508ed2..0dc46b589d 100644 --- a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/test/java/io/sermant/registry/inject/grace/SpringRequestInterceptorTest.java +++ b/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/test/java/io/sermant/registry/grace/interceptors/DispatcherServletInterceptorTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,8 +14,9 @@ * limitations under the License. */ -package io.sermant.registry.inject.grace; +package io.sermant.registry.grace.interceptors; +import io.sermant.core.plugin.agent.entity.ExecuteContext; import io.sermant.core.plugin.config.PluginConfigManager; import io.sermant.core.plugin.service.PluginServiceManager; import io.sermant.registry.config.GraceConfig; @@ -44,7 +45,7 @@ * @author zhouss * @since 2022-09-06 */ -public class SpringRequestInterceptorTest { +public class DispatcherServletInterceptorTest { private final String testAddress = "localhost:8099"; private final List addresses = new ArrayList<>(); @@ -63,7 +64,9 @@ public void addAddress(String address) { } }; - private SpringRequestInterceptor interceptor; + private ExecuteContext executeContext; + + private DispatcherServletInterceptor interceptor; @Mock private HttpServletRequest request; @@ -76,7 +79,7 @@ public void addAddress(String address) { private MockedStatic pluginConfigManagerMockedStatic; @Before - public void setUp() { + public void setUp() throws NoSuchMethodException { MockitoAnnotations.openMocks(this); pluginServiceManagerMockedStatic = Mockito.mockStatic(PluginServiceManager.class); pluginConfigManagerMockedStatic = Mockito.mockStatic(PluginConfigManager.class); @@ -91,7 +94,10 @@ public void setUp() { .thenReturn(GraceConstants.GRACE_OFFLINE_SOURCE_VALUE); Mockito.when(request.getHeader(GraceConstants.SERMANT_GRACE_ADDRESS)) .thenReturn(testAddress); - interceptor = new SpringRequestInterceptor(); + interceptor = new DispatcherServletInterceptor(); + Object[] arguments = new Object[]{request, response}; + executeContext = ExecuteContext.forMemberMethod(new Object(), String.class.getMethod("trim"), arguments, null, + null); } @After @@ -101,9 +107,9 @@ public void tearDown() throws Exception { } @Test - public void preHandle() { + public void before() { GraceContext.INSTANCE.getGraceShutDownManager().setShutDown(true); - interceptor.preHandle(request, response, new Object()); + interceptor.doBefore(executeContext); Assert.assertTrue(GraceContext.INSTANCE.getStartWarmUpTime() > 0); Assert.assertTrue(addresses.contains(testAddress)); Assert.assertTrue(GraceContext.INSTANCE.getGraceShutDownManager().getRequestCount() > 0); @@ -114,13 +120,13 @@ public void preHandle() { } @Test - public void postHandle() { - interceptor.postHandle(request, response, new Object(), null); + public void after() { + interceptor.doAfter(executeContext); } @Test - public void afterCompletion() { - interceptor.afterCompletion(request, response, new Object(), null); + public void doThrow() { + interceptor.doThrow(executeContext); Assert.assertTrue(GraceContext.INSTANCE.getGraceShutDownManager().getRequestCount() < 0); GraceContext.INSTANCE.getGraceShutDownManager().increaseRequestCount(); } diff --git a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/test/java/io/sermant/registry/grace/interceptors/SpringWebHandlerInterceptorTest.java b/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/test/java/io/sermant/registry/grace/interceptors/SpringWebHandlerInterceptorTest.java deleted file mode 100644 index 0b090b6a52..0000000000 --- a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/test/java/io/sermant/registry/grace/interceptors/SpringWebHandlerInterceptorTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package io.sermant.registry.grace.interceptors; - -import io.sermant.core.plugin.agent.entity.ExecuteContext; -import io.sermant.core.plugin.config.PluginConfigManager; -import io.sermant.core.plugin.service.PluginServiceManager; -import io.sermant.registry.config.GraceConfig; -import io.sermant.registry.config.RegisterConfig; -import io.sermant.registry.services.GraceService; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import org.springframework.web.servlet.HandlerExecutionChain; - -import java.util.Objects; - -/** - * Add an interceptor test - * - * @author zhouss - * @since 2022-06-30 - */ -public class SpringWebHandlerInterceptorTest { - private final GraceConfig graceConfig = new GraceConfig(); - - /** - * PluginConfigManager mock object - */ - public MockedStatic pluginConfigManagerMockedStatic; - - private MockedStatic pluginServiceManagerMockedStatic; - - /** - * Initialize - */ - @Before - public void init() { - graceConfig.setEnableSpring(true); - pluginConfigManagerMockedStatic = Mockito.mockStatic(PluginConfigManager.class); - pluginConfigManagerMockedStatic.when(() -> PluginConfigManager.getPluginConfig(GraceConfig.class)) - .thenReturn(graceConfig); - pluginConfigManagerMockedStatic.when(() -> PluginConfigManager.getPluginConfig(RegisterConfig.class)) - .thenReturn(new RegisterConfig()); - pluginServiceManagerMockedStatic = Mockito.mockStatic(PluginServiceManager.class); - pluginServiceManagerMockedStatic.when(() -> PluginServiceManager.getPluginService(GraceService.class)) - .thenReturn(new GraceService() { - @Override - public void shutdown() { - - } - - @Override - public void addAddress(String address) { - - } - }); - } - - @After - public void tearDown() { - pluginConfigManagerMockedStatic.close(); - pluginServiceManagerMockedStatic.close(); - } - - /** - * Test add interceptors - */ - @Test - public void testAddInterceptor() { - final HandlerExecutionChain chain = new HandlerExecutionChain(new Object()); - final ExecuteContext executeContext = ExecuteContext.forMemberMethod(chain, null, null, null, null); - final SpringWebHandlerInterceptor springWebHandlerInterceptor = new SpringWebHandlerInterceptor(); - springWebHandlerInterceptor.doBefore(executeContext); - Assert.assertTrue(Objects.requireNonNull(chain.getInterceptors()).length > 0); - } -}