This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-graalvm-distro.git


The following commit(s) were added to refs/heads/main by this push:
     new 7ae97f5  Bump upstream, enable gRPC TLS in native image, fix MAL 
closure wiring (#22)
7ae97f5 is described below

commit 7ae97f59e43ada1e92df218dd3e138083dcb85ca
Author: 吴晟 Wu Sheng <[email protected]>
AuthorDate: Thu Mar 19 22:42:02 2026 +0800

    Bump upstream, enable gRPC TLS in native image, fix MAL closure wiring (#22)
    
    feat(graalvm): enable gRPC TLS with JDK SSL and align with SkyWalking MAL v2
    
    - Bump `skywalking` submodule to `726ebcc321`
      - Includes upstream PR #13750 (MAL v2 companion class closures)
      - Syncs related UI updates
    
    - Add `library-server-for-graalvm` module
      - Provides same-FQCN `DynamicSslContext`
      - Uses `SslProvider.JDK` instead of `SslProvider.OPENSSL`
      - Enables gRPC TLS in native images without `netty_tcnative`
    
    - Add SSL e2e test (`ssl`)
      - Verifies gRPC TLS works with JDK SSL provider
      - Reuses upstream certs and `simple-cases.yaml`
    
    - Remove obsolete closure wiring
      - Drop `wireClosures()`, `CLOSURE_TYPES`, `ClosureInfo`
      - Clean up `DSL.java`, `MALScriptComparisonBase`,
        `PrecompiledMALExecutionTest`
      - Upstream now uses companion classes with self-wiring `static {}` blocks
    
    - Fix so11y e2e test
      - Re-enable `meter_oap_instance_metrics_aggregation`
      - Use label-filtered query: `{level='L1 aggregation'}`
    
    - Update SHA-256 tracking
      - Add `DynamicSslContext.java` to staleness detector
    
    - Update docs
      - Refresh CLAUDE.md for companion class pattern and TLS replacement
---
 .github/workflows/ci.yml                           |   2 +
 changes/changes.md                                 |   9 ++
 oap-graalvm-server/pom.xml                         |  10 ++
 .../src/main/assembly/distribution.xml             |   1 +
 oap-graalvm-server/src/test/CLAUDE.md              |   7 +-
 .../graalvm/PrecompiledMALExecutionTest.java       |  65 ----------
 .../graalvm/mal/MALScriptComparisonBase.java       |  76 ------------
 .../resources/replacement-source-sha256.properties |   4 +
 oap-libs-for-graalvm/CLAUDE.md                     |   8 +-
 .../library-server-for-graalvm/pom.xml             |  64 ++++++++++
 .../library/server/grpc/ssl/DynamicSslContext.java |  90 ++++++++++++++
 .../skywalking/oap/meter/analyzer/v2/dsl/DSL.java  |  94 +-------------
 oap-libs-for-graalvm/pom.xml                       |   1 +
 pom.xml                                            |  10 ++
 skywalking                                         |   2 +-
 test/e2e/cases/so11y/so11y-cases.yaml              |   3 +-
 test/e2e/cases/ssl/docker-compose.yml              | 136 +++++++++++++++++++++
 test/e2e/cases/ssl/e2e.yaml                        |  48 ++++++++
 18 files changed, 394 insertions(+), 236 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c0bbfd7..1d93dc6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -337,6 +337,8 @@ jobs:
             case: virtual-mq
           - name: Kafka Exporter
             case: exporter
+          - name: SSL
+            case: ssl
           - name: Self Observability
             case: so11y
           - name: MQE
diff --git a/changes/changes.md b/changes/changes.md
index 4ef2be3..c2d7a5e 100644
--- a/changes/changes.md
+++ b/changes/changes.md
@@ -2,12 +2,21 @@
 
 ## 0.3.0
 
+### Upstream Sync
+
+- Sync SkyWalking submodule to upstream commit `726ebcc321` (MAL v2 companion 
class closures).
+
+### GraalVM Native Image Compatibility
+
+- Add `library-server-for-graalvm`: replace `DynamicSslContext` to use 
`SslProvider.JDK` instead of `SslProvider.OPENSSL`, enabling gRPC TLS in native 
images without `netty_tcnative`.
+
 ### Documentation
 
 - Document TLS/SSL limitation: native image lacks `netty_tcnative`, recommend 
service mesh for mTLS.
 
 ### E2E Tests
 
+- Add SSL e2e test case (gRPC TLS with JDK SSL provider in native image).
 - Add Auth e2e test case (token-based agent-to-OAP authentication).
 - Add OTLP Traces e2e test case (OpenTelemetry trace ingestion via Zipkin API).
 - Add Virtual MQ e2e test case (Kafka-instrumented virtual MQ layer metrics).
diff --git a/oap-graalvm-server/pom.xml b/oap-graalvm-server/pom.xml
index 03ded8c..73c7552 100644
--- a/oap-graalvm-server/pom.xml
+++ b/oap-graalvm-server/pom.xml
@@ -45,6 +45,12 @@
                 <version>${skywalking.version}</version>
                 <scope>provided</scope>
             </dependency>
+            <dependency>
+                <groupId>org.apache.skywalking</groupId>
+                <artifactId>library-server</artifactId>
+                <version>${skywalking.version}</version>
+                <scope>provided</scope>
+            </dependency>
             <dependency>
                 <groupId>org.apache.skywalking</groupId>
                 <artifactId>server-core</artifactId>
@@ -126,6 +132,10 @@
             <groupId>org.apache.skywalking</groupId>
             <artifactId>library-module-for-graalvm</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.skywalking</groupId>
+            <artifactId>library-server-for-graalvm</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.skywalking</groupId>
             <artifactId>server-core-for-graalvm</artifactId>
diff --git a/oap-graalvm-server/src/main/assembly/distribution.xml 
b/oap-graalvm-server/src/main/assembly/distribution.xml
index 8f64d58..7c7995b 100644
--- a/oap-graalvm-server/src/main/assembly/distribution.xml
+++ b/oap-graalvm-server/src/main/assembly/distribution.xml
@@ -127,6 +127,7 @@
             <excludes>
                 <exclude>org.apache.skywalking:server-core</exclude>
                 <exclude>org.apache.skywalking:server-starter</exclude>
+                <exclude>org.apache.skywalking:library-server</exclude>
                 <exclude>org.apache.skywalking:library-util</exclude>
                 <exclude>org.apache.skywalking:meter-analyzer</exclude>
                 <exclude>org.apache.skywalking:log-analyzer</exclude>
diff --git a/oap-graalvm-server/src/test/CLAUDE.md 
b/oap-graalvm-server/src/test/CLAUDE.md
index 24d488a..ab8526b 100644
--- a/oap-graalvm-server/src/test/CLAUDE.md
+++ b/oap-graalvm-server/src/test/CLAUDE.md
@@ -34,9 +34,10 @@ Each metric expression is run through two independent paths:
 
 **Path B (Pre-compiled)**: Loads the `.class` file from per-file configs under
 `META-INF/mal-v2/` (mirroring original YAML directory structure) via
-`Class.forName()` using expression text as lookup key, then wires closure
-fields (TagFunction, ForEachFunction, PropertiesExtractor, DecorateFunction)
-via `LambdaMetafactory`.
+`Class.forName()` using expression text as lookup key. Closure fields
+(TagFunction, ForEachFunction, PropertiesExtractor, DecorateFunction) are
+self-wired via companion classes in the `static {}` initializer — no external
+`LambdaMetafactory` wiring needed.
 
 If both paths produce identical `Result` (same success flag, same sample values
 within 0.001 tolerance, same labels), then the build-time compilation is
diff --git 
a/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/PrecompiledMALExecutionTest.java
 
b/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/PrecompiledMALExecutionTest.java
index 7e5671d..a44aaf2 100644
--- 
a/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/PrecompiledMALExecutionTest.java
+++ 
b/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/PrecompiledMALExecutionTest.java
@@ -21,12 +21,6 @@ import com.google.common.collect.ImmutableMap;
 import java.io.BufferedReader;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.lang.invoke.CallSite;
-import java.lang.invoke.LambdaMetafactory;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import java.lang.reflect.Field;
 import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
@@ -37,7 +31,6 @@ import org.apache.skywalking.oap.meter.analyzer.v2.dsl.Result;
 import org.apache.skywalking.oap.meter.analyzer.v2.dsl.Sample;
 import org.apache.skywalking.oap.meter.analyzer.v2.dsl.SampleFamily;
 import org.apache.skywalking.oap.meter.analyzer.v2.dsl.SampleFamilyBuilder;
-import org.apache.skywalking.oap.meter.analyzer.v2.dsl.SampleFamilyFunctions;
 import org.apache.skywalking.oap.server.core.analysis.meter.MeterEntity;
 import org.apache.skywalking.oap.server.core.config.NamingControl;
 import org.apache.skywalking.oap.server.core.config.group.EndpointNameGrouping;
@@ -190,67 +183,9 @@ class PrecompiledMALExecutionTest {
 
         Class<?> exprClass = Class.forName(className);
         MalExpression malExpr = (MalExpression) 
exprClass.getDeclaredConstructor().newInstance();
-        wireClosures(exprClass, malExpr);
         return new Expression(metricName, expression, malExpr);
     }
 
-    private static final Map<String, ClosureInfo> CLOSURE_TYPES = new 
HashMap<>();
-
-    private record ClosureInfo(Class<?> interfaceClass, String samName,
-                               MethodType samType, MethodType instantiatedType,
-                               MethodType methodType) {
-    }
-
-    static {
-        CLOSURE_TYPES.put(
-            SampleFamilyFunctions.TagFunction.class.getName(),
-            new ClosureInfo(SampleFamilyFunctions.TagFunction.class, "apply",
-                MethodType.methodType(Object.class, Object.class),
-                MethodType.methodType(Map.class, Map.class),
-                MethodType.methodType(Map.class, Map.class)));
-        CLOSURE_TYPES.put(
-            SampleFamilyFunctions.PropertiesExtractor.class.getName(),
-            new ClosureInfo(SampleFamilyFunctions.PropertiesExtractor.class, 
"apply",
-                MethodType.methodType(Object.class, Object.class),
-                MethodType.methodType(Map.class, Map.class),
-                MethodType.methodType(Map.class, Map.class)));
-        CLOSURE_TYPES.put(
-            SampleFamilyFunctions.ForEachFunction.class.getName(),
-            new ClosureInfo(SampleFamilyFunctions.ForEachFunction.class, 
"accept",
-                MethodType.methodType(void.class, String.class, Map.class),
-                MethodType.methodType(void.class, String.class, Map.class),
-                MethodType.methodType(void.class, String.class, Map.class)));
-        CLOSURE_TYPES.put(
-            SampleFamilyFunctions.DecorateFunction.class.getName(),
-            new ClosureInfo(SampleFamilyFunctions.DecorateFunction.class, 
"accept",
-                MethodType.methodType(void.class, Object.class),
-                MethodType.methodType(void.class, Object.class),
-                MethodType.methodType(void.class, Object.class)));
-    }
-
-    private static void wireClosures(final Class<?> clazz, final Object 
instance) throws Exception {
-        try {
-            MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(clazz, 
MethodHandles.lookup());
-            for (Field field : clazz.getFields()) {
-                ClosureInfo info = 
CLOSURE_TYPES.get(field.getType().getName());
-                if (info == null) {
-                    continue;
-                }
-                String methodName = field.getName() + "_" + info.samName;
-                MethodHandle mh = lookup.findVirtual(clazz, methodName, 
info.methodType);
-                CallSite site = LambdaMetafactory.metafactory(
-                    lookup, info.samName,
-                    MethodType.methodType(info.interfaceClass, clazz),
-                    info.samType, mh, info.instantiatedType);
-                field.set(instance, site.getTarget().invoke(instance));
-            }
-        } catch (Exception e) {
-            throw e;
-        } catch (Throwable t) {
-            throw new RuntimeException("Failed to wire closures for " + 
clazz.getName(), t);
-        }
-    }
-
     private static Map<String, String> loadExpressionMap() throws Exception {
         Map<String, String> map = new HashMap<>();
         ClassLoader cl = PrecompiledMALExecutionTest.class.getClassLoader();
diff --git 
a/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/mal/MALScriptComparisonBase.java
 
b/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/mal/MALScriptComparisonBase.java
index 924c581..88b189d 100644
--- 
a/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/mal/MALScriptComparisonBase.java
+++ 
b/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/mal/MALScriptComparisonBase.java
@@ -22,12 +22,6 @@ import com.google.common.collect.ImmutableMap;
 import java.io.BufferedReader;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.lang.invoke.CallSite;
-import java.lang.invoke.LambdaMetafactory;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import java.lang.reflect.Field;
 import java.nio.charset.StandardCharsets;
 import java.time.Instant;
 import java.util.ArrayList;
@@ -48,7 +42,6 @@ import org.apache.skywalking.oap.meter.analyzer.v2.dsl.Result;
 import org.apache.skywalking.oap.meter.analyzer.v2.dsl.Sample;
 import org.apache.skywalking.oap.meter.analyzer.v2.dsl.SampleFamily;
 import org.apache.skywalking.oap.meter.analyzer.v2.dsl.SampleFamilyBuilder;
-import org.apache.skywalking.oap.meter.analyzer.v2.dsl.SampleFamilyFunctions;
 import org.apache.skywalking.oap.meter.analyzer.v2.prometheus.rule.MetricsRule;
 import org.apache.skywalking.oap.meter.analyzer.v2.prometheus.rule.Rule;
 import org.apache.skywalking.oap.server.core.analysis.meter.MeterEntity;
@@ -288,7 +281,6 @@ abstract class MALScriptComparisonBase {
             Class<?> exprClass = Class.forName(className);
             MalExpression malExpr =
                 (MalExpression) 
exprClass.getDeclaredConstructor().newInstance();
-            wireClosures(exprClass, malExpr);
             return new Expression(metricName, expression, malExpr);
         } catch (Exception e) {
             throw new AssertionError(
@@ -297,74 +289,6 @@ abstract class MALScriptComparisonBase {
         }
     }
 
-    // ---------------------------------------------------------------
-    // Closure wiring for pre-compiled classes
-    // ---------------------------------------------------------------
-
-    private record ClosureInfo(Class<?> interfaceClass, String samName,
-                               MethodType samType, MethodType instantiatedType,
-                               MethodType methodType) {
-    }
-
-    private static final Map<String, ClosureInfo> CLOSURE_TYPES = new 
HashMap<>();
-
-    static {
-        CLOSURE_TYPES.put(
-            SampleFamilyFunctions.TagFunction.class.getName(),
-            new ClosureInfo(SampleFamilyFunctions.TagFunction.class, "apply",
-                MethodType.methodType(Object.class, Object.class),
-                MethodType.methodType(Map.class, Map.class),
-                MethodType.methodType(Map.class, Map.class)));
-
-        CLOSURE_TYPES.put(
-            SampleFamilyFunctions.PropertiesExtractor.class.getName(),
-            new ClosureInfo(SampleFamilyFunctions.PropertiesExtractor.class, 
"apply",
-                MethodType.methodType(Object.class, Object.class),
-                MethodType.methodType(Map.class, Map.class),
-                MethodType.methodType(Map.class, Map.class)));
-
-        CLOSURE_TYPES.put(
-            SampleFamilyFunctions.ForEachFunction.class.getName(),
-            new ClosureInfo(SampleFamilyFunctions.ForEachFunction.class, 
"accept",
-                MethodType.methodType(void.class, String.class, Map.class),
-                MethodType.methodType(void.class, String.class, Map.class),
-                MethodType.methodType(void.class, String.class, Map.class)));
-
-        CLOSURE_TYPES.put(
-            SampleFamilyFunctions.DecorateFunction.class.getName(),
-            new ClosureInfo(SampleFamilyFunctions.DecorateFunction.class, 
"accept",
-                MethodType.methodType(void.class, Object.class),
-                MethodType.methodType(void.class, Object.class),
-                MethodType.methodType(void.class, Object.class)));
-    }
-
-    private static void wireClosures(final Class<?> clazz, final Object 
instance) {
-        try {
-            final MethodHandles.Lookup lookup =
-                MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
-
-            for (final Field field : clazz.getFields()) {
-                final ClosureInfo info = 
CLOSURE_TYPES.get(field.getType().getName());
-                if (info == null) {
-                    continue;
-                }
-                final String methodName = field.getName() + "_" + info.samName;
-                final MethodHandle mh = lookup.findVirtual(
-                    clazz, methodName, info.methodType);
-                final CallSite site = LambdaMetafactory.metafactory(
-                    lookup,
-                    info.samName,
-                    MethodType.methodType(info.interfaceClass, clazz),
-                    info.samType,
-                    mh,
-                    info.instantiatedType);
-                field.set(instance, site.getTarget().invoke(instance));
-            }
-        } catch (Throwable e) {
-            throw new AssertionError("Failed to wire closures for " + 
clazz.getName(), e);
-        }
-    }
-
     // ---------------------------------------------------------------
     // Input builders
     // ---------------------------------------------------------------
diff --git 
a/oap-graalvm-server/src/test/resources/replacement-source-sha256.properties 
b/oap-graalvm-server/src/test/resources/replacement-source-sha256.properties
index 53a6da6..8229f9b 100644
--- a/oap-graalvm-server/src/test/resources/replacement-source-sha256.properties
+++ b/oap-graalvm-server/src/test/resources/replacement-source-sha256.properties
@@ -61,6 +61,10 @@ 
skywalking/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalkin
 # Config loader: load from JSON manifests instead of filesystem YAML
 
skywalking/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/meter/config/MeterConfigs.java
 = 979b1d081a7e0aa1b627a525157d9f024f81a3db289e76284c54dbf508c494b1
 
+# --- library-server-for-graalvm ---
+# gRPC TLS: JDK SSL provider instead of OpenSSL (no netty_tcnative needed)
+skywalking/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/grpc/ssl/DynamicSslContext.java
 = d93a977d2282c7bfca309fe1fbdfb1f73d8c95f0d29be40a3f7bd837216563fe
+
 # --- library-module-for-graalvm ---
 # Direct provider wiring without ServiceLoader
 
skywalking/oap-server/server-library/library-module/src/main/java/org/apache/skywalking/oap/server/library/module/ModuleDefine.java
 = 89add3015c4265f50a13a9e5800d68aaa43e73f50c1224343712d2744b6e2437
diff --git a/oap-libs-for-graalvm/CLAUDE.md b/oap-libs-for-graalvm/CLAUDE.md
index fdc5cce..2c1aab7 100644
--- a/oap-libs-for-graalvm/CLAUDE.md
+++ b/oap-libs-for-graalvm/CLAUDE.md
@@ -54,11 +54,17 @@ JAVA_HOME=/Users/wusheng/.sdkman/candidates/java/25-graal 
make build-distro
 | `HierarchyService` | `server-core/.../hierarchy/HierarchyService.java` | 
Support for Java-backed closures | No |
 | `HttpAlarmCallback` | `server-core/.../alarm/HttpAlarmCallback.java` | Lazy 
HttpClient init (static final breaks in native image) | No |
 
+### library-server-for-graalvm (1 class)
+
+| Replacement Class | Upstream Source | Change | Staleness Tracked |
+|---|---|---|---|
+| `DynamicSslContext` | `library-server/.../grpc/ssl/DynamicSslContext.java` | 
`SslProvider.JDK` instead of `SslProvider.OPENSSL` (no `netty_tcnative` needed 
for native image) | **Yes** |
+
 ### meter-analyzer-for-graalvm (2 classes)
 
 | Replacement Class | Upstream Source | Change | Staleness Tracked |
 |---|---|---|---|
-| `DSL` | `meter-analyzer/.../v2/dsl/DSL.java` | Load pre-compiled 
`MalExpression` from per-file configs (`META-INF/mal-v2/`); look up by 
expression text; wires closure fields via `LambdaMetafactory` after 
instantiation | No |
+| `DSL` | `meter-analyzer/.../v2/dsl/DSL.java` | Load pre-compiled 
`MalExpression` from per-file configs (`META-INF/mal-v2/`); look up by 
expression text; closure fields are self-wired by companion classes in the 
static initializer (no `LambdaMetafactory`) | No |
 | `FilterExpression` | `meter-analyzer/.../v2/dsl/FilterExpression.java` | 
Load pre-compiled `MalFilter` from v2 manifest | No |
 
 ### log-analyzer-for-graalvm (1 class)
diff --git a/oap-libs-for-graalvm/library-server-for-graalvm/pom.xml 
b/oap-libs-for-graalvm/library-server-for-graalvm/pom.xml
new file mode 100644
index 0000000..6f1914d
--- /dev/null
+++ b/oap-libs-for-graalvm/library-server-for-graalvm/pom.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<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";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.skywalking</groupId>
+        <artifactId>oap-libs-for-graalvm</artifactId>
+        <version>0.3.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>library-server-for-graalvm</artifactId>
+    <name>Library Server for GraalVM</name>
+    <description>Repackaged library-server with DynamicSslContext using JDK 
SSL provider instead of OpenSSL</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.skywalking</groupId>
+            <artifactId>library-server</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <configuration>
+                    <artifactSet>
+                        <includes>
+                            
<include>org.apache.skywalking:library-server</include>
+                        </includes>
+                    </artifactSet>
+                    <filters>
+                        <filter>
+                            
<artifact>org.apache.skywalking:library-server</artifact>
+                            <excludes>
+                                
<exclude>org/apache/skywalking/oap/server/library/server/grpc/ssl/DynamicSslContext.class</exclude>
+                            </excludes>
+                        </filter>
+                    </filters>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git 
a/oap-libs-for-graalvm/library-server-for-graalvm/src/main/java/org/apache/skywalking/oap/server/library/server/grpc/ssl/DynamicSslContext.java
 
b/oap-libs-for-graalvm/library-server-for-graalvm/src/main/java/org/apache/skywalking/oap/server/library/server/grpc/ssl/DynamicSslContext.java
new file mode 100644
index 0000000..c255514
--- /dev/null
+++ 
b/oap-libs-for-graalvm/library-server-for-graalvm/src/main/java/org/apache/skywalking/oap/server/library/server/grpc/ssl/DynamicSslContext.java
@@ -0,0 +1,90 @@
+/*
+ * 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.library.server.grpc.ssl;
+
+import io.grpc.netty.GrpcSslContexts;
+import io.netty.handler.ssl.ClientAuth;
+import io.netty.handler.ssl.SslContextBuilder;
+import io.netty.handler.ssl.SslProvider;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Paths;
+import javax.net.ssl.SSLException;
+import org.apache.skywalking.oap.server.library.util.StringUtil;
+import org.apache.skywalking.oap.server.library.server.ssl.AbstractSslContext;
+import org.apache.skywalking.oap.server.library.server.ssl.PrivateKeyUtil;
+
+/**
+ * Same-FQCN replacement for upstream DynamicSslContext.
+ *
+ * <p>Uses {@link SslProvider#JDK} instead of {@link SslProvider#OPENSSL} so 
that
+ * gRPC TLS works in GraalVM native images without the {@code netty_tcnative}
+ * native library.
+ */
+public class DynamicSslContext extends AbstractSslContext {
+
+    public static DynamicSslContext forServer(final String privateKeyFile,
+                                              final String certChainFile,
+                                              final String trustedCAsFile) {
+        return new DynamicSslContext(privateKeyFile, certChainFile, 
trustedCAsFile);
+    }
+
+    public static DynamicSslContext forClient(final String caFile) {
+        return new DynamicSslContext(caFile);
+    }
+
+    protected DynamicSslContext(String privateKeyFile, String certChainFile, 
String trustedCAsFile) {
+        super(privateKeyFile, certChainFile, trustedCAsFile);
+    }
+
+    protected DynamicSslContext(String caFile) {
+        super(caFile);
+    }
+
+    @Override
+    protected void updateContext(String caFile) {
+        try {
+            
setCtx(GrpcSslContexts.forClient().trustManager(Paths.get(caFile).toFile()).build());
+        } catch (SSLException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    protected void updateContext(final String privateKeyFile, final String 
certChainFile, final String trustedCAsFile) {
+        try (InputStream cert = new 
FileInputStream(Paths.get(certChainFile).toFile());
+             InputStream key = 
PrivateKeyUtil.loadDecryptionKey(privateKeyFile)) {
+
+            SslContextBuilder builder = GrpcSslContexts.configure(
+                SslContextBuilder.forServer(cert, key),
+                SslProvider.JDK
+            );
+
+            if (StringUtil.isNotEmpty(trustedCAsFile)) {
+                builder.trustManager(Paths.get(trustedCAsFile).toFile())
+                    .clientAuth(ClientAuth.REQUIRE);
+            }
+
+            setCtx(builder.build());
+        } catch (IOException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+}
diff --git 
a/oap-libs-for-graalvm/meter-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/meter/analyzer/v2/dsl/DSL.java
 
b/oap-libs-for-graalvm/meter-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/meter/analyzer/v2/dsl/DSL.java
index 4cd9880..4421acb 100644
--- 
a/oap-libs-for-graalvm/meter-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/meter/analyzer/v2/dsl/DSL.java
+++ 
b/oap-libs-for-graalvm/meter-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/meter/analyzer/v2/dsl/DSL.java
@@ -21,12 +21,6 @@ import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.lang.invoke.CallSite;
-import java.lang.invoke.LambdaMetafactory;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import java.lang.reflect.Field;
 import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
@@ -48,6 +42,11 @@ import lombok.extern.slf4j.Slf4j;
  *
  * <p>At runtime, all per-file configs are loaded once and indexed by
  * expression text for O(1) lookup in {@link #parse(String, String, String)}.
+ *
+ * <p>Closure fields (TagFunction, ForEachFunction, etc.) are now self-wired
+ * via companion classes generated at build time. The main class static
+ * initializer instantiates each companion class directly — no external
+ * LambdaMetafactory wiring is needed.
  */
 @Slf4j
 public final class DSL {
@@ -76,7 +75,6 @@ public final class DSL {
         try {
             final Class<?> exprClass = Class.forName(className);
             final MalExpression malExpr = (MalExpression) 
exprClass.getDeclaredConstructor().newInstance();
-            wireClosures(exprClass, malExpr);
             final int count = LOADED_COUNT.incrementAndGet();
             log.debug("Loaded pre-compiled MAL expression [{}/{}]: {} -> {}",
                 count, EXPRESSION_MAP.size(), metricName, className);
@@ -179,86 +177,4 @@ public final class DSL {
             log.warn("Failed to load MAL v2 per-file config: {}", configPath, 
e);
         }
     }
-
-    /**
-     * Closure type metadata for LambdaMetafactory wiring.
-     * Maps functional interface type name to SAM method info.
-     */
-    private static final Map<String, ClosureInfo> CLOSURE_TYPES = new 
HashMap<>();
-
-    static {
-        // TagFunction extends Function<Map, Map>
-        CLOSURE_TYPES.put(
-            SampleFamilyFunctions.TagFunction.class.getName(),
-            new ClosureInfo(SampleFamilyFunctions.TagFunction.class, "apply",
-                MethodType.methodType(Object.class, Object.class),
-                MethodType.methodType(Map.class, Map.class),
-                MethodType.methodType(Map.class, Map.class)));
-
-        // PropertiesExtractor extends Function<Map, Map>
-        CLOSURE_TYPES.put(
-            SampleFamilyFunctions.PropertiesExtractor.class.getName(),
-            new ClosureInfo(SampleFamilyFunctions.PropertiesExtractor.class, 
"apply",
-                MethodType.methodType(Object.class, Object.class),
-                MethodType.methodType(Map.class, Map.class),
-                MethodType.methodType(Map.class, Map.class)));
-
-        // ForEachFunction — not generic, SAM = instantiated
-        CLOSURE_TYPES.put(
-            SampleFamilyFunctions.ForEachFunction.class.getName(),
-            new ClosureInfo(SampleFamilyFunctions.ForEachFunction.class, 
"accept",
-                MethodType.methodType(void.class, String.class, Map.class),
-                MethodType.methodType(void.class, String.class, Map.class),
-                MethodType.methodType(void.class, String.class, Map.class)));
-
-        // DecorateFunction extends Consumer<MeterEntity>
-        CLOSURE_TYPES.put(
-            SampleFamilyFunctions.DecorateFunction.class.getName(),
-            new ClosureInfo(SampleFamilyFunctions.DecorateFunction.class, 
"accept",
-                MethodType.methodType(void.class, Object.class),
-                MethodType.methodType(void.class, Object.class),
-                MethodType.methodType(void.class, Object.class)));
-    }
-
-    private record ClosureInfo(Class<?> interfaceClass, String samName,
-                               MethodType samType, MethodType instantiatedType,
-                               MethodType methodType) {
-    }
-
-    /**
-     * Wire closure fields on a pre-compiled MalExpression instance.
-     *
-     * <p>Generated classes have public fields typed as functional interfaces
-     * (TagFunction, ForEachFunction, etc.) with corresponding methods that
-     * implement the closure body. MALClassGenerator normally wires these via
-     * LambdaMetafactory after compilation. When loading from the manifest JAR,
-     * we replicate that wiring here.
-     */
-    static void wireClosures(final Class<?> clazz,
-                             final Object instance) {
-        try {
-            final MethodHandles.Lookup lookup =
-                MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
-
-            for (final Field field : clazz.getFields()) {
-                final ClosureInfo info = 
CLOSURE_TYPES.get(field.getType().getName());
-                if (info == null) {
-                    continue;
-                }
-                final String methodName = field.getName() + "_" + info.samName;
-                final MethodHandle mh = lookup.findVirtual(
-                    clazz, methodName, info.methodType);
-                final CallSite site = LambdaMetafactory.metafactory(
-                    lookup,
-                    info.samName,
-                    MethodType.methodType(info.interfaceClass, clazz),
-                    info.samType,
-                    mh,
-                    info.instantiatedType);
-                field.set(instance, site.getTarget().invoke(instance));
-            }
-        } catch (Throwable e) {
-            log.warn("Failed to wire closures for {}", clazz.getName(), e);
-        }
-    }
 }
diff --git a/oap-libs-for-graalvm/pom.xml b/oap-libs-for-graalvm/pom.xml
index 95f8176..100794c 100644
--- a/oap-libs-for-graalvm/pom.xml
+++ b/oap-libs-for-graalvm/pom.xml
@@ -35,6 +35,7 @@
     <modules>
         <module>server-core-for-graalvm</module>
         <module>library-module-for-graalvm</module>
+        <module>library-server-for-graalvm</module>
         <module>library-util-for-graalvm</module>
         <module>meter-analyzer-for-graalvm</module>
         <module>log-analyzer-for-graalvm</module>
diff --git a/pom.xml b/pom.xml
index 68e32ec..ddcd2ba 100644
--- a/pom.xml
+++ b/pom.xml
@@ -112,6 +112,11 @@
                 <artifactId>library-module</artifactId>
                 <version>${skywalking.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.skywalking</groupId>
+                <artifactId>library-server</artifactId>
+                <version>${skywalking.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.skywalking</groupId>
                 <artifactId>library-util</artifactId>
@@ -378,6 +383,11 @@
                 <artifactId>library-module-for-graalvm</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.skywalking</groupId>
+                <artifactId>library-server-for-graalvm</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.skywalking</groupId>
                 <artifactId>library-util-for-graalvm</artifactId>
diff --git a/skywalking b/skywalking
index 64a1795..726ebcc 160000
--- a/skywalking
+++ b/skywalking
@@ -1 +1 @@
-Subproject commit 64a1795d8a582f2216f47bfe572b3ab649733c01
+Subproject commit 726ebcc321dbd3c258963fc4bc23d320b903f6d9
diff --git a/test/e2e/cases/so11y/so11y-cases.yaml 
b/test/e2e/cases/so11y/so11y-cases.yaml
index e1fd1c3..698938d 100644
--- a/test/e2e/cases/so11y/so11y-cases.yaml
+++ b/test/e2e/cases/so11y/so11y-cases.yaml
@@ -29,7 +29,8 @@
     # OAP application-level metrics (available in native image)
     - query: swctl --display yaml 
--base-url=http://${oap_host}:${oap_12800}/graphql metrics exec 
--expression=meter_oap_instance_trace_count 
--instance-name=http://localhost:1234 --service-name=oap-server
       expected: 
../../../../skywalking/test/e2e-v2/cases/so11y/expected/metrics-has-value-label-trace.yml
-    # meter_oap_instance_metrics_aggregation skipped: .tag() closure NPE in 
pre-compiled MAL
+    - query: swctl --display yaml 
--base-url=http://${oap_host}:${oap_12800}/graphql metrics exec 
--expression="meter_oap_instance_metrics_aggregation{level='L1 aggregation'}" 
--instance-name=http://localhost:1234 --service-name=oap-server
+      expected: 
../../../../skywalking/test/e2e-v2/cases/so11y/expected/metrics-has-value-label.yml
     - query: swctl --display yaml 
--base-url=http://${oap_host}:${oap_12800}/graphql metrics exec 
--expression=meter_oap_instance_persistence_prepare_count 
--instance-name=http://localhost:1234 --service-name=oap-server
       expected: 
../../../../skywalking/test/e2e-v2/cases/so11y/expected/metrics-has-value.yml
     - query: swctl --display yaml 
--base-url=http://${oap_host}:${oap_12800}/graphql metrics exec 
--expression=meter_oap_instance_persistence_execute_count 
--instance-name=http://localhost:1234 --service-name=oap-server
diff --git a/test/e2e/cases/ssl/docker-compose.yml 
b/test/e2e/cases/ssl/docker-compose.yml
new file mode 100644
index 0000000..b446950
--- /dev/null
+++ b/test/e2e/cases/ssl/docker-compose.yml
@@ -0,0 +1,136 @@
+# 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.
+
+services:
+  banyandb:
+    extends:
+      file: 
../../../../skywalking/test/e2e-v2/script/docker-compose/base-compose.yml
+      service: banyandb
+    ports:
+      - 17912
+
+  oap:
+    image: skywalking-oap-native:latest
+    volumes:
+      - 
../../../../skywalking/test/e2e-v2/cases/simple/ssl/certs:/skywalking/certs
+    expose:
+      - 11800
+      - 12800
+    networks:
+      - e2e
+    ports:
+      - 12800
+    environment:
+      SW_HEALTH_CHECKER: default
+      SW_STORAGE_BANYANDB_TARGETS: banyandb:17912
+      SW_CONFIGURATION: none
+      SW_CORE_GRPC_SSL_ENABLED: "true"
+      SW_CORE_GRPC_SSL_KEY_PATH: /skywalking/certs/server-key.pem
+      SW_CORE_GRPC_SSL_CERT_CHAIN_PATH: /skywalking/certs/server.crt
+      SW_CORE_GRPC_SSL_TRUSTED_CA_PATH: /skywalking/certs/ca.crt
+    depends_on:
+      banyandb:
+        condition: service_healthy
+    healthcheck:
+      test: ["CMD-SHELL", "nc -nz 127.0.0.1 11800 || exit 1"]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+
+  # Init containers: copy pre-built service JARs into a shared volume
+  provider-jar:
+    image: 
"ghcr.io/apache/skywalking/e2e-service-provider:${SW_E2E_SERVICE_COMMIT}"
+    entrypoint: ["cp", "/app.jar", "/jars/services_provider.jar"]
+    volumes:
+      - service-jars:/jars
+    networks:
+      - e2e
+
+  consumer-jar:
+    image: 
"ghcr.io/apache/skywalking/e2e-service-consumer:${SW_E2E_SERVICE_COMMIT}"
+    entrypoint: ["cp", "/app.jar", "/jars/services_consumer.jar"]
+    volumes:
+      - service-jars:/jars
+    networks:
+      - e2e
+
+  provider:
+    image: 
"ghcr.io/apache/skywalking-java/skywalking-java:${SW_AGENT_JAVA_COMMIT}-java${SW_AGENT_JDK_VERSION}"
+    command: ["java", "-jar", "/jars/services_provider.jar"]
+    volumes:
+      - service-jars:/jars
+      - 
../../../../skywalking/test/e2e-v2/cases/simple/ssl/ca:/skywalking/agent/ca
+    networks:
+      - e2e
+    expose:
+      - 9090
+    ports:
+      - 9090
+    environment:
+      SW_AGENT_COLLECTOR_BACKEND_SERVICES: oap:11800
+      SW_LOGGING_OUTPUT: CONSOLE
+      SW_AGENT_NAME: e2e-service-provider
+      SW_AGENT_INSTANCE_NAME: provider1
+      SW_AGENT_COLLECTOR_GET_PROFILE_TASK_INTERVAL: 1
+      SW_AGENT_COLLECTOR_GET_AGENT_DYNAMIC_CONFIG_INTERVAL: 1
+      SW_METER_ACTIVE: 'false'
+    healthcheck:
+      test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/9090"]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+    depends_on:
+      oap:
+        condition: service_healthy
+      provider-jar:
+        condition: service_completed_successfully
+
+  consumer:
+    image: 
"ghcr.io/apache/skywalking-java/skywalking-java:${SW_AGENT_JAVA_COMMIT}-java${SW_AGENT_JDK_VERSION}"
+    command: ["java", "-jar", "/jars/services_consumer.jar"]
+    volumes:
+      - service-jars:/jars
+      - 
../../../../skywalking/test/e2e-v2/cases/simple/ssl/ca:/skywalking/agent/ca
+    networks:
+      - e2e
+    expose:
+      - 9092
+    ports:
+      - 9092
+    environment:
+      SW_AGENT_COLLECTOR_BACKEND_SERVICES: oap:11800
+      SW_LOGGING_OUTPUT: CONSOLE
+      PROVIDER_URL: http://provider:9090
+      SW_AGENT_NAME: e2e-service-consumer
+      SW_AGENT_INSTANCE_NAME: consumer1
+      SW_AGENT_COLLECTOR_GET_PROFILE_TASK_INTERVAL: 1
+      SW_AGENT_COLLECTOR_GET_AGENT_DYNAMIC_CONFIG_INTERVAL: 1
+      SW_METER_ACTIVE: 'false'
+    healthcheck:
+      test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/9092"]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+    depends_on:
+      provider:
+        condition: service_healthy
+      consumer-jar:
+        condition: service_completed_successfully
+
+volumes:
+  service-jars:
+
+networks:
+  e2e:
diff --git a/test/e2e/cases/ssl/e2e.yaml b/test/e2e/cases/ssl/e2e.yaml
new file mode 100644
index 0000000..33723a8
--- /dev/null
+++ b/test/e2e/cases/ssl/e2e.yaml
@@ -0,0 +1,48 @@
+# 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.
+
+# SSL E2E — native OAP with gRPC TLS enabled (JDK SSL provider).
+# Verifies that agents can report traces over TLS-encrypted gRPC.
+
+setup:
+  env: compose
+  file: docker-compose.yml
+  timeout: 20m
+  init-system-environment: ../../script/env
+  steps:
+    - name: set PATH
+      command: export PATH=/tmp/skywalking-infra-e2e/bin:$PATH
+    - name: install yq
+      command: bash 
skywalking/test/e2e-v2/script/prepare/setup-e2e-shell/install.sh yq
+    - name: install swctl
+      command: bash 
skywalking/test/e2e-v2/script/prepare/setup-e2e-shell/install.sh swctl
+
+trigger:
+  action: http
+  interval: 3s
+  times: -1
+  url: http://${consumer_host}:${consumer_9092}/users
+  method: POST
+  body: '{"id":"123","name":"skywalking"}'
+  headers:
+    "Content-Type": "application/json"
+
+verify:
+  retry:
+    count: 20
+    interval: 3s
+  cases:
+    - includes:
+        - ../../../../skywalking/test/e2e-v2/cases/simple/simple-cases.yaml


Reply via email to