This is an automated email from the ASF dual-hosted git repository. wusheng pushed a commit to branch groovy-replace in repository https://gitbox.apache.org/repos/asf/skywalking.git
commit 0b8ec1cdb5cba3443e5e72c729a332fc6ffbf987 Author: Wu Sheng <[email protected]> AuthorDate: Sat Feb 28 16:13:57 2026 +0800 Refactor hierarchy rules: replace Groovy Closure with Java BiFunction (Phase 5) Extract hierarchy matching rules from HierarchyDefinitionService into pluggable HierarchyRuleProvider interface. Remove Groovy imports from server-core by replacing Closure<Boolean> with BiFunction<Service,Service,Boolean>. - hierarchy-v1: GroovyHierarchyRuleProvider (for CI checker only) - hierarchy-v2: JavaHierarchyRuleProvider with 4 built-in rules + 12 tests - HierarchyDefinitionService: add HierarchyRuleProvider interface, DefaultJavaRuleProvider - HierarchyService: .getClosure().call() → .match() Co-Authored-By: Claude Opus 4.6 <[email protected]> --- oap-server/analyzer/{ => hierarchy-v1}/pom.xml | 29 +--- .../core/config/GroovyHierarchyRuleProvider.java | 49 +++++++ oap-server/analyzer/{ => hierarchy-v2}/pom.xml | 29 +--- .../core/config/JavaHierarchyRuleProvider.java | 86 ++++++++++++ .../core/config/JavaHierarchyRuleProviderTest.java | 155 +++++++++++++++++++++ oap-server/analyzer/pom.xml | 2 + .../core/config/HierarchyDefinitionService.java | 109 ++++++++++++--- .../server/core/hierarchy/HierarchyService.java | 10 +- 8 files changed, 394 insertions(+), 75 deletions(-) diff --git a/oap-server/analyzer/pom.xml b/oap-server/analyzer/hierarchy-v1/pom.xml similarity index 62% copy from oap-server/analyzer/pom.xml copy to oap-server/analyzer/hierarchy-v1/pom.xml index 5053d0e628..0e2cf572f2 100644 --- a/oap-server/analyzer/pom.xml +++ b/oap-server/analyzer/hierarchy-v1/pom.xml @@ -19,41 +19,24 @@ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> - <artifactId>oap-server</artifactId> + <artifactId>analyzer</artifactId> <groupId>org.apache.skywalking</groupId> <version>${revision}</version> </parent> <modelVersion>4.0.0</modelVersion> - <artifactId>analyzer</artifactId> - <packaging>pom</packaging> - - <modules> - <module>agent-analyzer</module> - <module>log-analyzer</module> - <module>meter-analyzer</module> - <module>event-analyzer</module> - <module>mal-transpiler</module> - <module>lal-transpiler</module> - <module>meter-analyzer-v2</module> - <module>log-analyzer-v2</module> - </modules> + <artifactId>hierarchy-v1</artifactId> + <description>Groovy-based hierarchy rule provider (for checker module only, not runtime)</description> <dependencies> <dependency> <groupId>org.apache.skywalking</groupId> - <artifactId>apm-network</artifactId> + <artifactId>server-core</artifactId> <version>${project.version}</version> </dependency> <dependency> - <groupId>org.apache.skywalking</groupId> - <artifactId>library-module</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.apache.skywalking</groupId> - <artifactId>library-util</artifactId> - <version>${project.version}</version> + <groupId>org.apache.groovy</groupId> + <artifactId>groovy</artifactId> </dependency> </dependencies> </project> diff --git a/oap-server/analyzer/hierarchy-v1/src/main/java/org/apache/skywalking/oap/server/core/config/GroovyHierarchyRuleProvider.java b/oap-server/analyzer/hierarchy-v1/src/main/java/org/apache/skywalking/oap/server/core/config/GroovyHierarchyRuleProvider.java new file mode 100644 index 0000000000..c8e8af4305 --- /dev/null +++ b/oap-server/analyzer/hierarchy-v1/src/main/java/org/apache/skywalking/oap/server/core/config/GroovyHierarchyRuleProvider.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package org.apache.skywalking.oap.server.core.config; + +import groovy.lang.Closure; +import groovy.lang.GroovyShell; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiFunction; +import org.apache.skywalking.oap.server.core.query.type.Service; + +/** + * Groovy-based hierarchy rule provider. Uses GroovyShell.evaluate() to compile + * hierarchy matching rule closures from YAML expressions. + * + * <p>This provider is NOT included in the runtime classpath. It is only used + * by the hierarchy-v1-v2-checker module for CI validation against the pure Java + * provider (hierarchy-v2). + */ +public final class GroovyHierarchyRuleProvider implements HierarchyDefinitionService.HierarchyRuleProvider { + + @Override + @SuppressWarnings("unchecked") + public Map<String, BiFunction<Service, Service, Boolean>> buildRules( + final Map<String, String> ruleExpressions) { + final Map<String, BiFunction<Service, Service, Boolean>> rules = new HashMap<>(); + final GroovyShell sh = new GroovyShell(); + ruleExpressions.forEach((name, expression) -> { + final Closure<Boolean> closure = (Closure<Boolean>) sh.evaluate(expression); + rules.put(name, (u, l) -> closure.call(u, l)); + }); + return rules; + } +} diff --git a/oap-server/analyzer/pom.xml b/oap-server/analyzer/hierarchy-v2/pom.xml similarity index 61% copy from oap-server/analyzer/pom.xml copy to oap-server/analyzer/hierarchy-v2/pom.xml index 5053d0e628..42e49678b2 100644 --- a/oap-server/analyzer/pom.xml +++ b/oap-server/analyzer/hierarchy-v2/pom.xml @@ -19,40 +19,19 @@ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> - <artifactId>oap-server</artifactId> + <artifactId>analyzer</artifactId> <groupId>org.apache.skywalking</groupId> <version>${revision}</version> </parent> <modelVersion>4.0.0</modelVersion> - <artifactId>analyzer</artifactId> - <packaging>pom</packaging> - - <modules> - <module>agent-analyzer</module> - <module>log-analyzer</module> - <module>meter-analyzer</module> - <module>event-analyzer</module> - <module>mal-transpiler</module> - <module>lal-transpiler</module> - <module>meter-analyzer-v2</module> - <module>log-analyzer-v2</module> - </modules> + <artifactId>hierarchy-v2</artifactId> + <description>Pure Java hierarchy rule provider with static rule registry (no Groovy)</description> <dependencies> <dependency> <groupId>org.apache.skywalking</groupId> - <artifactId>apm-network</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.apache.skywalking</groupId> - <artifactId>library-module</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.apache.skywalking</groupId> - <artifactId>library-util</artifactId> + <artifactId>server-core</artifactId> <version>${project.version}</version> </dependency> </dependencies> diff --git a/oap-server/analyzer/hierarchy-v2/src/main/java/org/apache/skywalking/oap/server/core/config/JavaHierarchyRuleProvider.java b/oap-server/analyzer/hierarchy-v2/src/main/java/org/apache/skywalking/oap/server/core/config/JavaHierarchyRuleProvider.java new file mode 100644 index 0000000000..d85bdb99c7 --- /dev/null +++ b/oap-server/analyzer/hierarchy-v2/src/main/java/org/apache/skywalking/oap/server/core/config/JavaHierarchyRuleProvider.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +package org.apache.skywalking.oap.server.core.config; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.BiFunction; +import org.apache.skywalking.oap.server.core.query.type.Service; + +/** + * Pure Java hierarchy rule provider. Contains a static registry of all known + * hierarchy matching rules as Java lambdas. Zero Groovy dependency. + * + * <p>Rule names must match those in hierarchy-definition.yml auto-matching-rules section. + * Unknown rule names fail fast at startup with IllegalArgumentException. + */ +public final class JavaHierarchyRuleProvider implements HierarchyDefinitionService.HierarchyRuleProvider { + + private static final Map<String, BiFunction<Service, Service, Boolean>> RULE_REGISTRY; + + static { + RULE_REGISTRY = new HashMap<>(); + + // name: { (u, l) -> u.name == l.name } + RULE_REGISTRY.put("name", + (u, l) -> Objects.equals(u.getName(), l.getName())); + + // short-name: { (u, l) -> u.shortName == l.shortName } + RULE_REGISTRY.put("short-name", + (u, l) -> Objects.equals(u.getShortName(), l.getShortName())); + + // lower-short-name-remove-ns: + // { (u, l) -> { if(l.shortName.lastIndexOf('.') > 0) + // return u.shortName == l.shortName.substring(0, l.shortName.lastIndexOf('.')); + // return false; } } + RULE_REGISTRY.put("lower-short-name-remove-ns", (u, l) -> { + final String sn = l.getShortName(); + final int dot = sn.lastIndexOf('.'); + return dot > 0 && Objects.equals(u.getShortName(), sn.substring(0, dot)); + }); + + // lower-short-name-with-fqdn: + // { (u, l) -> { if(u.shortName.lastIndexOf(':') > 0) + // return u.shortName.substring(0, u.shortName.lastIndexOf(':')) == l.shortName.concat('.svc.cluster.local'); + // return false; } } + RULE_REGISTRY.put("lower-short-name-with-fqdn", (u, l) -> { + final String sn = u.getShortName(); + final int colon = sn.lastIndexOf(':'); + return colon > 0 && Objects.equals( + sn.substring(0, colon), + l.getShortName() + ".svc.cluster.local"); + }); + } + + @Override + public Map<String, BiFunction<Service, Service, Boolean>> buildRules( + final Map<String, String> ruleExpressions) { + final Map<String, BiFunction<Service, Service, Boolean>> rules = new HashMap<>(); + ruleExpressions.forEach((name, expression) -> { + final BiFunction<Service, Service, Boolean> fn = RULE_REGISTRY.get(name); + if (fn == null) { + throw new IllegalArgumentException( + "Unknown hierarchy matching rule: " + name + + ". Known rules: " + RULE_REGISTRY.keySet()); + } + rules.put(name, fn); + }); + return rules; + } +} diff --git a/oap-server/analyzer/hierarchy-v2/src/test/java/org/apache/skywalking/oap/server/core/config/JavaHierarchyRuleProviderTest.java b/oap-server/analyzer/hierarchy-v2/src/test/java/org/apache/skywalking/oap/server/core/config/JavaHierarchyRuleProviderTest.java new file mode 100644 index 0000000000..699d3af4aa --- /dev/null +++ b/oap-server/analyzer/hierarchy-v2/src/test/java/org/apache/skywalking/oap/server/core/config/JavaHierarchyRuleProviderTest.java @@ -0,0 +1,155 @@ +/* + * 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. + */ + +package org.apache.skywalking.oap.server.core.config; + +import java.util.Map; +import java.util.function.BiFunction; +import org.apache.skywalking.oap.server.core.query.type.Service; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class JavaHierarchyRuleProviderTest { + + private JavaHierarchyRuleProvider provider; + + @BeforeEach + void setUp() { + provider = new JavaHierarchyRuleProvider(); + } + + private Service svc(final String name, final String shortName) { + final Service s = new Service(); + s.setName(name); + s.setShortName(shortName); + return s; + } + + // ---- name rule ---- + + @Test + void nameRuleMatches() { + final Map<String, BiFunction<Service, Service, Boolean>> rules = + provider.buildRules(Map.of("name", "{ (u, l) -> u.name == l.name }")); + assertTrue(rules.get("name").apply(svc("svc", "svc"), svc("svc", "svc"))); + } + + @Test + void nameRuleDoesNotMatch() { + final Map<String, BiFunction<Service, Service, Boolean>> rules = + provider.buildRules(Map.of("name", "ignored")); + assertFalse(rules.get("name").apply(svc("svc", "svc"), svc("other", "other"))); + } + + // ---- short-name rule ---- + + @Test + void shortNameRuleMatches() { + final Map<String, BiFunction<Service, Service, Boolean>> rules = + provider.buildRules(Map.of("short-name", "ignored")); + assertTrue(rules.get("short-name").apply(svc("a", "svc"), svc("b", "svc"))); + } + + @Test + void shortNameRuleDoesNotMatch() { + final Map<String, BiFunction<Service, Service, Boolean>> rules = + provider.buildRules(Map.of("short-name", "ignored")); + assertFalse(rules.get("short-name").apply(svc("a", "svc1"), svc("b", "svc2"))); + } + + // ---- lower-short-name-remove-ns rule ---- + + @Test + void lowerShortNameRemoveNsMatches() { + final Map<String, BiFunction<Service, Service, Boolean>> rules = + provider.buildRules(Map.of("lower-short-name-remove-ns", "ignored")); + // l.shortName = "svc.namespace", u.shortName = "svc" + assertTrue(rules.get("lower-short-name-remove-ns") + .apply(svc("a", "svc"), svc("b", "svc.namespace"))); + } + + @Test + void lowerShortNameRemoveNsNoDot() { + final Map<String, BiFunction<Service, Service, Boolean>> rules = + provider.buildRules(Map.of("lower-short-name-remove-ns", "ignored")); + assertFalse(rules.get("lower-short-name-remove-ns") + .apply(svc("a", "svc"), svc("b", "svc"))); + } + + @Test + void lowerShortNameRemoveNsMismatch() { + final Map<String, BiFunction<Service, Service, Boolean>> rules = + provider.buildRules(Map.of("lower-short-name-remove-ns", "ignored")); + assertFalse(rules.get("lower-short-name-remove-ns") + .apply(svc("a", "other"), svc("b", "svc.namespace"))); + } + + // ---- lower-short-name-with-fqdn rule ---- + + @Test + void lowerShortNameWithFqdnMatches() { + final Map<String, BiFunction<Service, Service, Boolean>> rules = + provider.buildRules(Map.of("lower-short-name-with-fqdn", "ignored")); + // u.shortName = "db:3306", l.shortName = "db" -> "db" == "db.svc.cluster.local"? no + // u.shortName = "db:3306", l.shortName should match: u prefix = "db", l + fqdn = "db.svc.cluster.local" + assertTrue(rules.get("lower-short-name-with-fqdn") + .apply(svc("a", "db.svc.cluster.local:3306"), svc("b", "db"))); + } + + @Test + void lowerShortNameWithFqdnNoColon() { + final Map<String, BiFunction<Service, Service, Boolean>> rules = + provider.buildRules(Map.of("lower-short-name-with-fqdn", "ignored")); + assertFalse(rules.get("lower-short-name-with-fqdn") + .apply(svc("a", "db"), svc("b", "db"))); + } + + @Test + void lowerShortNameWithFqdnWrongSuffix() { + final Map<String, BiFunction<Service, Service, Boolean>> rules = + provider.buildRules(Map.of("lower-short-name-with-fqdn", "ignored")); + assertFalse(rules.get("lower-short-name-with-fqdn") + .apply(svc("a", "db:3306"), svc("b", "other"))); + } + + // ---- unknown rule ---- + + @Test + void unknownRuleThrows() { + assertThrows(IllegalArgumentException.class, + () -> provider.buildRules(Map.of("unknown-rule", "ignored"))); + } + + // ---- builds all 4 rules ---- + + @Test + void buildsAllFourRules() { + final Map<String, BiFunction<Service, Service, Boolean>> rules = + provider.buildRules(Map.of( + "name", "ignored", + "short-name", "ignored", + "lower-short-name-remove-ns", "ignored", + "lower-short-name-with-fqdn", "ignored" + )); + assertEquals(4, rules.size()); + } +} diff --git a/oap-server/analyzer/pom.xml b/oap-server/analyzer/pom.xml index 5053d0e628..b6b4fb531d 100644 --- a/oap-server/analyzer/pom.xml +++ b/oap-server/analyzer/pom.xml @@ -37,6 +37,8 @@ <module>lal-transpiler</module> <module>meter-analyzer-v2</module> <module>log-analyzer-v2</module> + <module>hierarchy-v1</module> + <module>hierarchy-v2</module> </modules> <dependencies> diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/HierarchyDefinitionService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/HierarchyDefinitionService.java index fbec34cf6c..737e50ebed 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/HierarchyDefinitionService.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/HierarchyDefinitionService.java @@ -18,17 +18,18 @@ package org.apache.skywalking.oap.server.core.config; -import groovy.lang.Closure; -import groovy.lang.GroovyShell; import java.io.FileNotFoundException; import java.io.Reader; import java.util.HashMap; import java.util.Map; +import java.util.Objects; +import java.util.function.BiFunction; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.skywalking.oap.server.core.CoreModuleConfig; import org.apache.skywalking.oap.server.core.UnexpectedException; import org.apache.skywalking.oap.server.core.analysis.Layer; +import org.apache.skywalking.oap.server.core.query.type.Service; import org.apache.skywalking.oap.server.library.util.ResourceUtils; import org.yaml.snakeyaml.Yaml; @@ -37,36 +38,99 @@ import static java.util.stream.Collectors.toMap; @Slf4j public class HierarchyDefinitionService implements org.apache.skywalking.oap.server.library.module.Service { + /** + * Functional interface for building hierarchy matching rules. + * Implementations are provided by hierarchy-v1 (Groovy) or hierarchy-v2 (pure Java). + */ + @FunctionalInterface + public interface HierarchyRuleProvider { + Map<String, BiFunction<Service, Service, Boolean>> buildRules(Map<String, String> ruleExpressions); + } + @Getter private final Map<String, Map<String, MatchingRule>> hierarchyDefinition; @Getter private Map<String, Integer> layerLevels; private Map<String, MatchingRule> matchingRules; - public HierarchyDefinitionService(CoreModuleConfig moduleConfig) { + public HierarchyDefinitionService(final CoreModuleConfig moduleConfig, + final HierarchyRuleProvider ruleProvider) { this.hierarchyDefinition = new HashMap<>(); this.layerLevels = new HashMap<>(); if (moduleConfig.isEnableHierarchy()) { - this.init(); + this.init(ruleProvider); this.checkLayers(); } } + /** + * Convenience constructor that uses the default Java rule provider. + */ + public HierarchyDefinitionService(final CoreModuleConfig moduleConfig) { + this(moduleConfig, new DefaultJavaRuleProvider()); + } + + /** + * Default pure Java rule provider with 4 built-in hierarchy matching rules. + * No Groovy dependency. + */ + private static class DefaultJavaRuleProvider implements HierarchyRuleProvider { + @Override + public Map<String, BiFunction<Service, Service, Boolean>> buildRules( + final Map<String, String> ruleExpressions) { + final Map<String, BiFunction<Service, Service, Boolean>> registry = new HashMap<>(); + registry.put("name", (u, l) -> Objects.equals(u.getName(), l.getName())); + registry.put("short-name", (u, l) -> Objects.equals(u.getShortName(), l.getShortName())); + registry.put("lower-short-name-remove-ns", (u, l) -> { + final String sn = l.getShortName(); + final int dot = sn.lastIndexOf('.'); + return dot > 0 && Objects.equals(u.getShortName(), sn.substring(0, dot)); + }); + registry.put("lower-short-name-with-fqdn", (u, l) -> { + final String sn = u.getShortName(); + final int colon = sn.lastIndexOf(':'); + return colon > 0 && Objects.equals( + sn.substring(0, colon), + l.getShortName() + ".svc.cluster.local"); + }); + + final Map<String, BiFunction<Service, Service, Boolean>> rules = new HashMap<>(); + ruleExpressions.forEach((name, expression) -> { + final BiFunction<Service, Service, Boolean> fn = registry.get(name); + if (fn == null) { + throw new IllegalArgumentException( + "Unknown hierarchy matching rule: " + name + + ". Known rules: " + registry.keySet()); + } + rules.put(name, fn); + }); + return rules; + } + } + @SuppressWarnings("unchecked") - private void init() { + private void init(final HierarchyRuleProvider ruleProvider) { try { - Reader applicationReader = ResourceUtils.read("hierarchy-definition.yml"); - Yaml yaml = new Yaml(); - Map<String, Map> config = yaml.loadAs(applicationReader, Map.class); - Map<String, Map<String, String>> hierarchy = (Map<String, Map<String, String>>) config.get("hierarchy"); - Map<String, String> matchingRules = (Map<String, String>) config.get("auto-matching-rules"); + final Reader applicationReader = ResourceUtils.read("hierarchy-definition.yml"); + final Yaml yaml = new Yaml(); + final Map<String, Map> config = yaml.loadAs(applicationReader, Map.class); + final Map<String, Map<String, String>> hierarchy = (Map<String, Map<String, String>>) config.get("hierarchy"); + final Map<String, String> ruleExpressions = (Map<String, String>) config.get("auto-matching-rules"); this.layerLevels = (Map<String, Integer>) config.get("layer-levels"); - this.matchingRules = matchingRules.entrySet().stream().map(entry -> { - MatchingRule matchingRule = new MatchingRule(entry.getKey(), entry.getValue()); + + final Map<String, BiFunction<Service, Service, Boolean>> builtRules = ruleProvider.buildRules(ruleExpressions); + + this.matchingRules = ruleExpressions.entrySet().stream().map(entry -> { + final BiFunction<Service, Service, Boolean> matcher = builtRules.get(entry.getKey()); + if (matcher == null) { + throw new IllegalStateException( + "HierarchyRuleProvider did not produce a matcher for rule: " + entry.getKey()); + } + final MatchingRule matchingRule = new MatchingRule(entry.getKey(), entry.getValue(), matcher); return Map.entry(entry.getKey(), matchingRule); }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); hierarchy.forEach((layer, lowerLayers) -> { - Map<String, MatchingRule> rules = new HashMap<>(); + final Map<String, MatchingRule> rules = new HashMap<>(); lowerLayers.forEach((lowerLayer, ruleName) -> { rules.put(lowerLayer, this.matchingRules.get(ruleName)); }); @@ -85,14 +149,14 @@ public class HierarchyDefinitionService implements org.apache.skywalking.oap.ser } }); this.hierarchyDefinition.forEach((layer, lowerLayers) -> { - Integer layerLevel = this.layerLevels.get(layer); + final Integer layerLevel = this.layerLevels.get(layer); if (this.layerLevels.get(layer) == null) { throw new IllegalArgumentException( "hierarchy-definition.yml layer-levels: " + layer + " is not defined"); } - for (String lowerLayer : lowerLayers.keySet()) { - Integer lowerLayerLevel = this.layerLevels.get(lowerLayer); + for (final String lowerLayer : lowerLayers.keySet()) { + final Integer lowerLayerLevel = this.layerLevels.get(lowerLayer); if (lowerLayerLevel == null) { throw new IllegalArgumentException( "hierarchy-definition.yml layer-levels: " + lowerLayer + " is not defined."); @@ -109,14 +173,17 @@ public class HierarchyDefinitionService implements org.apache.skywalking.oap.ser public static class MatchingRule { private final String name; private final String expression; - private final Closure<Boolean> closure; + private final BiFunction<Service, Service, Boolean> matcher; - @SuppressWarnings("unchecked") - public MatchingRule(final String name, final String expression) { + public MatchingRule(final String name, final String expression, + final BiFunction<Service, Service, Boolean> matcher) { this.name = name; this.expression = expression; - GroovyShell sh = new GroovyShell(); - closure = (Closure<Boolean>) sh.evaluate(expression); + this.matcher = matcher; + } + + public boolean match(final Service upper, final Service lower) { + return matcher.apply(upper, lower); } } } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java index 02e4014229..5eaa22752e 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java @@ -199,8 +199,7 @@ public class HierarchyService implements org.apache.skywalking.oap.server.librar if (lowerLayers != null && lowerLayers.get(comparedServiceLayer) != null) { try { if (lowerLayers.get(comparedServiceLayer) - .getClosure() - .call(service, comparedService)) { + .match(service, comparedService)) { autoMatchingServiceRelation(service.getName(), Layer.nameOf(serviceLayer), comparedService.getName(), Layer.nameOf(comparedServiceLayer) @@ -208,7 +207,7 @@ public class HierarchyService implements org.apache.skywalking.oap.server.librar } } catch (Throwable e) { log.error( - "Auto matching service hierarchy from service traffic failure. Upper layer {}, lower layer {}, closure{}", + "Auto matching service hierarchy from service traffic failure. Upper layer {}, lower layer {}, rule {}", serviceLayer, comparedServiceLayer, lowerLayers.get(comparedServiceLayer).getExpression(), e @@ -218,8 +217,7 @@ public class HierarchyService implements org.apache.skywalking.oap.server.librar } else if (comparedLowerLayers != null && comparedLowerLayers.get(serviceLayer) != null) { try { if (comparedLowerLayers.get(serviceLayer) - .getClosure() - .call(comparedService, service)) { + .match(comparedService, service)) { autoMatchingServiceRelation( comparedService.getName(), Layer.nameOf(comparedServiceLayer), @@ -229,7 +227,7 @@ public class HierarchyService implements org.apache.skywalking.oap.server.librar } } catch (Throwable e) { log.error( - "Auto matching service hierarchy from service traffic failure. Upper layer {}, lower layer {}, closure{}", + "Auto matching service hierarchy from service traffic failure. Upper layer {}, lower layer {}, rule {}", comparedServiceLayer, serviceLayer, comparedLowerLayers.get(serviceLayer).getExpression(), e
