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 9b68f0e  Distro packaging: version, log4j2, alarm config, and 
native-image readiness
9b68f0e is described below

commit 9b68f0e5cc62d6132315b5bda75aadc1c9068bb1
Author: Wu Sheng <[email protected]>
AuthorDate: Tue Feb 24 11:57:25 2026 +0800

    Distro packaging: version, log4j2, alarm config, and native-image readiness
    
    - version.properties: copy from submodule, replace -SNAPSHOT with short
      commit ID, append -graal-distro suffix (e.g. 10.4.0-b537891-graal-distro).
      Placed in config/ (first on classpath) to shadow any JAR copies.
    
    - server-starter-for-graalvm: repackaged server-starter via shade plugin
      with version.properties excluded, preventing classpath conflict in both
      JVM distro and native-image builds. Original server-starter excluded
      from assembly and marked provided in oap-graalvm-native.
    
    - log4j2.xml and alarm-settings.yml now sourced from dist-material/
      (production configs) instead of server-starter/ (dev configs), matching
      upstream apm-dist packaging. dist-material log4j2 uses RollingFile
      appender at INFO level with no custom %swversion plugin dependency.
    
    - sw.version system property set in GraalVMOAPServerStartUp.main() before
      log4j2 init, enabling ${sys:sw.version} in log patterns as a standard
      log4j2 lookup replacement for the custom VersionLogConverter plugin.
    
    - Makefile build-distro: add oap-libs-for-graalvm child module build
      phase to ensure all for-graalvm shaded JARs are installed.
    
    - StorageBuilder scan in precompiler for native-image reflection config.
    
    - FieldsHelper same-FQCN replacement, NoneConfigurationProvider support,
      native-image build args (AddAllCharsets, URL protocols).
---
 Makefile                                           |   1 +
 .../server/buildtools/precompiler/Precompiler.java |  48 +++++
 oap-graalvm-native/pom.xml                         |  10 ++
 .../oap-graalvm-native/reflect-config.json         |  44 +++++
 oap-graalvm-server/pom.xml                         |  48 ++++-
 .../src/main/assembly/distribution.xml             |  29 +++-
 .../server/graalvm/GraalVMOAPServerStartUp.java    |  15 +-
 .../oap/server/library/util/FieldsHelper.java      | 193 +++++++++++++++++++++
 .../src/main/resources/application.yml             |   1 +
 .../library-util-for-graalvm/pom.xml               |   2 +
 oap-libs-for-graalvm/pom.xml                       |   1 +
 .../pom.xml                                        |  19 +-
 pom.xml                                            |   5 +
 13 files changed, 395 insertions(+), 21 deletions(-)

diff --git a/Makefile b/Makefile
index 1ef37aa..011cfb3 100644
--- a/Makefile
+++ b/Makefile
@@ -55,6 +55,7 @@ javadoc:
 # Phase 2: package oap-graalvm-server and oap-graalvm-native with assembly.
 build-distro:
        $(MVN) clean install -pl oap-libs-for-graalvm -am -DskipTests 
$(MVN_ARGS)
+       $(MVN) install -f oap-libs-for-graalvm -DskipTests $(MVN_ARGS)
        $(MVN) package -pl oap-graalvm-server,oap-graalvm-native -DskipTests 
$(MVN_ARGS)
 
 # Show the distribution directory
diff --git 
a/build-tools/precompiler/src/main/java/org/apache/skywalking/oap/server/buildtools/precompiler/Precompiler.java
 
b/build-tools/precompiler/src/main/java/org/apache/skywalking/oap/server/buildtools/precompiler/Precompiler.java
index 957a09a..766d785 100644
--- 
a/build-tools/precompiler/src/main/java/org/apache/skywalking/oap/server/buildtools/precompiler/Precompiler.java
+++ 
b/build-tools/precompiler/src/main/java/org/apache/skywalking/oap/server/buildtools/precompiler/Precompiler.java
@@ -191,6 +191,11 @@ public class Precompiler {
         writeManifest(annotationScanDir.resolve("MeterFunction.txt"),
             scanMeterFunctions(allClasses));
 
+        // StorageBuilder scan: extract builder() class from @Stream 
annotations
+        // These are instantiated via getDeclaredConstructor().newInstance() 
at runtime
+        writeManifest(annotationScanDir.resolve("StorageBuilders.txt"),
+            scanStorageBuilders(allClasses));
+
         // ---- MAL pre-compilation ----
         compileMAL(outputDir, allClasses);
 
@@ -745,6 +750,46 @@ public class Precompiler {
         return result;
     }
 
+    /**
+     * Scan @Stream-annotated classes for their builder() class reference, and
+     * @MeterFunction-annotated classes for their AcceptableValue.builder() 
return type.
+     * These StorageBuilder classes are instantiated via 
getDeclaredConstructor().newInstance()
+     * at runtime and need reflection registration for native image.
+     */
+    private static List<String> scanStorageBuilders(
+        ImmutableSet<ClassPath.ClassInfo> allClasses) {
+
+        List<String> result = new ArrayList<>();
+        for (ClassPath.ClassInfo classInfo : allClasses) {
+            try {
+                Class<?> aClass = classInfo.load();
+                // @Stream-annotated classes declare builder in annotation
+                if 
(aClass.isAnnotationPresent(org.apache.skywalking.oap.server.core.analysis.Stream.class))
 {
+                    org.apache.skywalking.oap.server.core.analysis.Stream 
stream =
+                        
aClass.getAnnotation(org.apache.skywalking.oap.server.core.analysis.Stream.class);
+                    Class<?> builderClass = stream.builder();
+                    if (builderClass != null && builderClass != void.class) {
+                        result.add(builderClass.getName());
+                    }
+                }
+                // @MeterFunction classes have StorageBuilder inner classes
+                if (aClass.isAnnotationPresent(MeterFunction.class)) {
+                    for (Class<?> inner : aClass.getDeclaredClasses()) {
+                        if 
(org.apache.skywalking.oap.server.core.storage.type.StorageBuilder.class
+                                .isAssignableFrom(inner)) {
+                            result.add(inner.getName());
+                        }
+                    }
+                }
+            } catch (NoClassDefFoundError | Exception ignored) {
+            }
+        }
+        // Deduplicate (multiple @Stream classes may share the same builder)
+        result = 
result.stream().distinct().sorted().collect(Collectors.toList());
+        log.info("Scanned StorageBuilder classes: {} unique entries", 
result.size());
+        return result;
+    }
+
     /**
      * Serialize MAL config data (Rules and MeterConfigs) as JSON for runtime 
loaders.
      * At runtime, replacement loader classes deserialize from these JSON 
files instead
@@ -884,6 +929,9 @@ public class Precompiler {
             }
         }
 
+        // StorageBuilder classes — constructor-only (instantiated via 
getDeclaredConstructor().newInstance())
+        addConstructorEntries(entries, 
annotationScanDir.resolve("StorageBuilders.txt"));
+
         // OAL metrics and dispatchers — constructor-only
         addConstructorEntries(entries, 
metaInf.resolve("oal-metrics-classes.txt"));
         addConstructorEntries(entries, 
metaInf.resolve("oal-dispatcher-classes.txt"));
diff --git a/oap-graalvm-native/pom.xml b/oap-graalvm-native/pom.xml
index 6359a58..7f4de45 100644
--- a/oap-graalvm-native/pom.xml
+++ b/oap-graalvm-native/pom.xml
@@ -36,6 +36,14 @@
             <groupId>org.apache.skywalking</groupId>
             <artifactId>oap-graalvm-server</artifactId>
         </dependency>
+        <!-- Override transitive server-starter (which contains a conflicting
+             version.properties) with provided scope. The repackaged
+             server-starter-for-graalvm (without version.properties) is used 
instead. -->
+        <dependency>
+            <groupId>org.apache.skywalking</groupId>
+            <artifactId>server-starter</artifactId>
+            <scope>provided</scope>
+        </dependency>
         <!-- Override transitive groovy (compile) from server-core to test 
scope.
              Runtime uses groovy-stubs instead. -->
         <dependency>
@@ -70,6 +78,8 @@
                                 <buildArg>--no-fallback</buildArg>
                                 <buildArg>--verbose</buildArg>
                                 
<buildArg>-H:+ReportExceptionStackTraces</buildArg>
+                                <buildArg>-H:+AddAllCharsets</buildArg>
+                                
<buildArg>--enable-url-protocols=https,http</buildArg>
                             </buildArgs>
                         </configuration>
                         <executions>
diff --git 
a/oap-graalvm-native/src/main/resources/META-INF/native-image/org.apache.skywalking/oap-graalvm-native/reflect-config.json
 
b/oap-graalvm-native/src/main/resources/META-INF/native-image/org.apache.skywalking/oap-graalvm-native/reflect-config.json
new file mode 100644
index 0000000..2da0b03
--- /dev/null
+++ 
b/oap-graalvm-native/src/main/resources/META-INF/native-image/org.apache.skywalking/oap-graalvm-native/reflect-config.json
@@ -0,0 +1,44 @@
+[
+  {
+    "name": "org.apache.skywalking.oap.log.analyzer.provider.LALConfigs",
+    "allDeclaredFields": true,
+    "allDeclaredMethods": true,
+    "allDeclaredConstructors": true
+  },
+  {
+    "name": "org.apache.skywalking.oap.log.analyzer.provider.LALConfig",
+    "allDeclaredFields": true,
+    "allDeclaredMethods": true,
+    "allDeclaredConstructors": true
+  },
+  {
+    "name": 
"org.apache.skywalking.oap.server.analyzer.provider.meter.config.MeterConfig",
+    "allDeclaredFields": true,
+    "allDeclaredMethods": true,
+    "allDeclaredConstructors": true
+  },
+  {
+    "name": "org.apache.skywalking.oap.meter.analyzer.prometheus.rule.Rule",
+    "allDeclaredFields": true,
+    "allDeclaredMethods": true,
+    "allDeclaredConstructors": true
+  },
+  {
+    "name": 
"org.apache.skywalking.oap.meter.analyzer.prometheus.rule.MetricsRule",
+    "allDeclaredFields": true,
+    "allDeclaredMethods": true,
+    "allDeclaredConstructors": true
+  },
+  {
+    "name": 
"org.apache.skywalking.oap.server.core.management.ui.menu.UIMenuInitializer$MenuData",
+    "allDeclaredFields": true,
+    "allDeclaredMethods": true,
+    "allDeclaredConstructors": true
+  },
+  {
+    "name": 
"org.apache.skywalking.oap.server.core.management.ui.menu.UIMenuItemSetting",
+    "allDeclaredFields": true,
+    "allDeclaredMethods": true,
+    "allDeclaredConstructors": true
+  }
+]
diff --git a/oap-graalvm-server/pom.xml b/oap-graalvm-server/pom.xml
index 6e48d82..316bd19 100644
--- a/oap-graalvm-server/pom.xml
+++ b/oap-graalvm-server/pom.xml
@@ -117,6 +117,12 @@
                 <version>${skywalking.version}</version>
                 <scope>provided</scope>
             </dependency>
+            <dependency>
+                <groupId>org.apache.skywalking</groupId>
+                <artifactId>server-starter</artifactId>
+                <version>${skywalking.version}</version>
+                <scope>provided</scope>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 
@@ -340,10 +346,10 @@
             <artifactId>ai-pipeline</artifactId>
         </dependency>
 
-        <!-- Server Starter (for ApplicationConfigLoader) -->
+        <!-- Server Starter (for ApplicationConfigLoader, version.properties 
excluded) -->
         <dependency>
             <groupId>org.apache.skywalking</groupId>
-            <artifactId>server-starter</artifactId>
+            <artifactId>server-starter-for-graalvm</artifactId>
         </dependency>
 
         <!-- Pre-compiled classes + manifests from build-time precompiler -->
@@ -462,6 +468,44 @@
                             </target>
                         </configuration>
                     </execution>
+                    <!-- Copy version.properties from submodule, patch version 
for graal-distro.
+                         If version has -SNAPSHOT, replace it with the short 
commit ID.
+                         e.g. 10.4.0-SNAPSHOT -> 10.4.0-b537891-graal-distro
+                         Release versions just get the suffix: 10.4.0 -> 
10.4.0-graal-distro -->
+                    <execution>
+                        <id>copy-version-properties</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>run</goal>
+                        </goals>
+                        <configuration>
+                            <target>
+                                <copy 
file="${project.basedir}/../skywalking/oap-server/server-starter/src/main/resources/version.properties"
+                                      
tofile="${project.build.outputDirectory}/version.properties"
+                                      overwrite="true"/>
+                                <!-- Load the commit id from the copied file 
-->
+                                <loadproperties 
srcFile="${project.build.outputDirectory}/version.properties"
+                                                prefix="upstream."/>
+                                <!-- Extract first 7 chars of commit id -->
+                                <loadresource 
property="upstream.git.commit.id.short">
+                                    <string value="${upstream.git.commit.id}"/>
+                                    <filterchain>
+                                        <replaceregex pattern="^(.{7}).*$" 
replace="\1"/>
+                                    </filterchain>
+                                </loadresource>
+                                <!-- Replace -SNAPSHOT with -<short-commit> 
(only matches if -SNAPSHOT exists) -->
+                                <replaceregexp 
file="${project.build.outputDirectory}/version.properties"
+                                               
match="^(git\.build\.version=.*)-SNAPSHOT$"
+                                               
replace="\1-${upstream.git.commit.id.short}"
+                                               byline="true"/>
+                                <!-- Append -graal-distro suffix -->
+                                <replaceregexp 
file="${project.build.outputDirectory}/version.properties"
+                                               
match="^(git\.build\.version=.+)$"
+                                               replace="\1-graal-distro"
+                                               byline="true"/>
+                            </target>
+                        </configuration>
+                    </execution>
                 </executions>
             </plugin>
             <!-- Assemble distribution folder: bin/ + config/ + libs/ + 
VERSION -->
diff --git a/oap-graalvm-server/src/main/assembly/distribution.xml 
b/oap-graalvm-server/src/main/assembly/distribution.xml
index 3f4ae8a..8f64d58 100644
--- a/oap-graalvm-server/src/main/assembly/distribution.xml
+++ b/oap-graalvm-server/src/main/assembly/distribution.xml
@@ -50,10 +50,32 @@
                 <include>application.yml</include>
             </includes>
         </fileSet>
+        <!-- config/ — patched version.properties (graal-distro suffix).
+             Placed in config/ which is first on the classpath, ensuring it 
takes
+             precedence over the original version.properties in server-starter 
JAR. -->
+        <fileSet>
+            <directory>${project.build.outputDirectory}</directory>
+            <outputDirectory>config</outputDirectory>
+            <includes>
+                <include>version.properties</include>
+            </includes>
+        </fileSet>
+        <!-- config/ — production configs from dist-material (same as upstream 
apm-dist).
+             These override server-starter versions: dist-material has 
production-ready
+             logging (RollingFile, INFO level) and alarm rules. -->
+        <fileSet>
+            
<directory>${project.basedir}/../skywalking/dist-material</directory>
+            <outputDirectory>config</outputDirectory>
+            <includes>
+                <include>log4j2.xml</include>
+                <include>alarm-settings.yml</include>
+            </includes>
+        </fileSet>
         <!-- config/ — upstream resource files loaded at runtime.
              OAL/MAL/LAL scripts are NOT included — they are pre-compiled at 
build time
              and loaded from manifests + pre-compiled .class files in JARs.
-             Only runtime config files (loaded via ResourceUtils.read()) are 
packaged. -->
+             Only runtime config files (loaded via ResourceUtils.read()) are 
packaged.
+             log4j2.xml and alarm-settings.yml come from dist-material above. 
-->
         <fileSet>
             
<directory>${project.basedir}/../skywalking/oap-server/server-starter/src/main/resources</directory>
             <outputDirectory>config</outputDirectory>
@@ -61,16 +83,12 @@
                 <!-- BanyanDB storage config (loaded by BanyanDBConfigLoader) 
-->
                 <include>bydb.yml</include>
                 <include>bydb-topn.yml</include>
-                <!-- Logging -->
-                <include>log4j2.xml</include>
                 <!-- UI dashboard templates (loaded by UITemplateInitializer) 
-->
                 <include>ui-initialized-templates/**</include>
                 <!-- Cilium rules (loaded by CiliumFetcherProvider) -->
                 <include>cilium-rules/**</include>
                 <!-- OpenAPI endpoint grouping definitions -->
                 <include>openapi-definitions/**</include>
-                <!-- Alarm rules (loaded by AlarmModuleProvider) -->
-                <include>alarm-settings.yml</include>
                 <!-- Component library definitions (loaded by 
ComponentLibraryCatalogService) -->
                 <include>component-libraries.yml</include>
                 <!-- Endpoint name grouping (loaded by 
EndpointNameGroupingRuleWatcher) -->
@@ -108,6 +126,7 @@
             <useProjectArtifact>true</useProjectArtifact>
             <excludes>
                 <exclude>org.apache.skywalking:server-core</exclude>
+                <exclude>org.apache.skywalking:server-starter</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/main/java/org/apache/skywalking/oap/server/graalvm/GraalVMOAPServerStartUp.java
 
b/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/graalvm/GraalVMOAPServerStartUp.java
index 0c2e825..96ddd8f 100644
--- 
a/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/graalvm/GraalVMOAPServerStartUp.java
+++ 
b/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/graalvm/GraalVMOAPServerStartUp.java
@@ -18,6 +18,7 @@
 package org.apache.skywalking.oap.server.graalvm;
 
 import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.core.version.Version;
 import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.CoreModuleProvider;
 import org.apache.skywalking.oap.server.core.RunningMode;
@@ -42,6 +43,7 @@ import 
org.apache.skywalking.oap.server.cluster.plugin.standalone.ClusterModuleS
 import 
org.apache.skywalking.oap.server.cluster.plugin.kubernetes.ClusterModuleKubernetesProvider;
 // Configuration
 import org.apache.skywalking.oap.server.configuration.api.ConfigurationModule;
+import 
org.apache.skywalking.oap.server.configuration.api.NoneConfigurationProvider;
 import 
org.apache.skywalking.oap.server.configuration.configmap.ConfigmapConfigurationProvider;
 // Telemetry
 import org.apache.skywalking.oap.server.telemetry.TelemetryModule;
@@ -128,6 +130,10 @@ import 
org.apache.skywalking.oap.server.ai.pipeline.AIPipelineProvider;
 public class GraalVMOAPServerStartUp {
 
     public static void main(String[] args) {
+        // Expose version as system property so log4j2 patterns can use 
${sys:sw.version}
+        // instead of the custom %swversion converter that requires plugin 
discovery.
+        System.setProperty("sw.version", Version.CURRENT.toString());
+
         // Ensure Log4j2 finds its config from the filesystem config/ 
directory.
         // In JVM mode config/ is on the classpath; native images have no 
classpath.
         if (System.getProperty("log4j2.configurationFile") == null) {
@@ -189,8 +195,13 @@ public class GraalVMOAPServerStartUp {
         }
         // Storage: BanyanDB
         manager.register(new StorageModule(), new BanyanDBStorageProvider());
-        // Configuration: Kubernetes ConfigMap
-        manager.register(new ConfigurationModule(), new 
ConfigmapConfigurationProvider());
+        // Configuration: Kubernetes ConfigMap or None
+        ApplicationConfiguration.ModuleConfiguration configConfig = 
configuration.getModuleConfiguration("configuration");
+        if (configConfig != null && configConfig.has("k8s-configmap")) {
+            manager.register(new ConfigurationModule(), new 
ConfigmapConfigurationProvider());
+        } else {
+            manager.register(new ConfigurationModule(), new 
NoneConfigurationProvider());
+        }
         // Telemetry: Prometheus
         manager.register(new TelemetryModule(), new 
PrometheusTelemetryProvider());
 
diff --git 
a/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/util/FieldsHelper.java
 
b/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/util/FieldsHelper.java
new file mode 100644
index 0000000..b9db45c
--- /dev/null
+++ 
b/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/util/FieldsHelper.java
@@ -0,0 +1,193 @@
+/*
+ * 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.util;
+
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.protobuf.Struct;
+import com.google.protobuf.Value;
+import lombok.RequiredArgsConstructor;
+import lombok.experimental.Delegate;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.InputStream;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * Same-FQCN replacement for native-image compatibility.
+ *
+ * <p>Upstream uses {@code LambdaMetafactory.metafactory()} to create setter
+ * wrappers at runtime, which fails in GraalVM native images (cannot define
+ * classes at runtime). This replacement uses {@link MethodHandle#invoke()}
+ * directly, which is supported by GraalVM.
+ */
+@Slf4j
+public class FieldsHelper {
+
+    private static final Map<Class<?>, FieldsHelper> HELPER_MAP = new 
ConcurrentHashMap<>();
+
+    private final Class<?> targetClass;
+    private boolean initialized = false;
+    private Map<String, FieldFormat> fieldNameMapping;
+    private Map<String, BiConsumer<Object, String>> fieldSetterMapping;
+
+    public static FieldsHelper forClass(final Class<?> targetClass) {
+        return HELPER_MAP.computeIfAbsent(targetClass, FieldsHelper::new);
+    }
+
+    private FieldsHelper(Class<?> targetClass) {
+        this.targetClass = targetClass;
+    }
+
+    public void init(final String file) throws Exception {
+        init(ResourceUtils.readToStream(file));
+    }
+
+    public void init(final InputStream inputStream) {
+        if (initialized) {
+            return;
+        }
+
+        final Yaml yaml = new Yaml();
+        final Map<String, String> config = yaml.load(inputStream);
+
+        fieldNameMapping = new HashMap<>(config.size());
+        fieldSetterMapping = new HashMap<>(config.size());
+
+        for (final Map.Entry<String, String> entry : config.entrySet()) {
+            final String serviceMetaInfoFieldName = entry.getKey();
+            final String flatBuffersFieldName = entry.getValue();
+
+            final Pattern p = Pattern.compile("(\\$\\{(?<properties>.+?)})");
+            final Matcher m = p.matcher(flatBuffersFieldName);
+            final List<Property> flatBuffersFieldNames = new 
ArrayList<>(m.groupCount());
+            final StringBuffer serviceNamePattern = new StringBuffer();
+            while (m.find()) {
+                final String properties = m.group("properties");
+                final List<Field> fields = 
Splitter.on(',').omitEmptyStrings().splitToList(properties).stream().map(candidate
 -> {
+                    List<String> tokens = 
Splitter.on('.').omitEmptyStrings().splitToList(candidate);
+
+                    StringBuilder tokenBuffer = new StringBuilder();
+                    List<String> candidateFields = new 
ArrayList<>(tokens.size());
+                    for (String token : tokens) {
+                        if (tokenBuffer.length() == 0 && 
token.startsWith("\"")) {
+                            tokenBuffer.append(token);
+                        } else if (tokenBuffer.length() > 0) {
+                            tokenBuffer.append(".").append(token);
+                        } else {
+                            candidateFields.add(token);
+                        }
+
+                        if (tokenBuffer.length() > 0 && token.endsWith("\"")) {
+                            
candidateFields.add(tokenBuffer.toString().replaceAll("\"", ""));
+                            tokenBuffer.setLength(0);
+                        }
+                    }
+                    return new Field(candidateFields);
+                }).collect(Collectors.toList());
+                flatBuffersFieldNames.add(new Property(fields));
+                m.appendReplacement(serviceNamePattern, "%s");
+            }
+
+            fieldNameMapping.put(
+                serviceMetaInfoFieldName,
+                new FieldFormat(serviceNamePattern.toString(), 
flatBuffersFieldNames)
+            );
+
+            try {
+                final String setter = "set" + 
StringUtils.capitalize(serviceMetaInfoFieldName);
+                final MethodHandles.Lookup lookup = MethodHandles.lookup();
+                final MethodHandle mh = lookup.findVirtual(
+                    targetClass, setter, MethodType.methodType(void.class, 
String.class));
+                // Wrap MethodHandle in a BiConsumer without LambdaMetafactory
+                fieldSetterMapping.put(serviceMetaInfoFieldName, (obj, val) -> 
{
+                    try {
+                        mh.invoke(obj, val);
+                    } catch (Throwable t) {
+                        throw new RuntimeException("Failed to invoke " + 
setter, t);
+                    }
+                });
+            } catch (final Throwable e) {
+                throw new IllegalStateException("Initialize method error", e);
+            }
+        }
+        initialized = true;
+    }
+
+    public void inflate(final Struct metadata, final Object target) {
+        final Value empty = Value.newBuilder().setStringValue("-").build();
+        final Value root = Value.newBuilder().setStructValue(metadata).build();
+        for (final var entry : fieldNameMapping.entrySet()) {
+            final FieldFormat fieldFormat = entry.getValue();
+            final Object[] values = new String[fieldFormat.properties.size()];
+            for (int i = 0; i < fieldFormat.properties.size(); i++) {
+                values[i] = "-";
+                final Property property = fieldFormat.properties.get(i);
+                for (final Field field : property) {
+                    Value value = root;
+                    for (final String segment : field.dsvSegments) {
+                        final var fieldMaps = new TreeMap<String, 
Value>(String.CASE_INSENSITIVE_ORDER);
+                        
fieldMaps.putAll(value.getStructValue().getFieldsMap());
+                        value = fieldMaps.getOrDefault(segment, empty);
+                    }
+                    if (Strings.isNullOrEmpty(value.getStringValue()) || 
"-".equals(value.getStringValue())) {
+                        continue;
+                    }
+                    values[i] = value.getStringValue();
+                    break;
+                }
+            }
+            final String value = Strings.lenientFormat(fieldFormat.format, 
values);
+            if (!Strings.isNullOrEmpty(value)) {
+                fieldSetterMapping.get(entry.getKey()).accept(target, value);
+            }
+        }
+    }
+
+    @RequiredArgsConstructor
+    private static class FieldFormat {
+        private final String format;
+        private final List<Property> properties;
+    }
+
+    @RequiredArgsConstructor
+    private static class Property implements Iterable<Field> {
+        @Delegate
+        private final List<Field> candidateFields;
+    }
+
+    @RequiredArgsConstructor
+    private static class Field implements Iterable<String> {
+        @Delegate
+        private final List<String> dsvSegments;
+    }
+}
diff --git a/oap-graalvm-server/src/main/resources/application.yml 
b/oap-graalvm-server/src/main/resources/application.yml
index eedc328..704fa98 100644
--- a/oap-graalvm-server/src/main/resources/application.yml
+++ b/oap-graalvm-server/src/main/resources/application.yml
@@ -315,6 +315,7 @@ telemetry:
 
 configuration:
   selector: ${SW_CONFIGURATION:k8s-configmap}
+  none:
   k8s-configmap:
     period: ${SW_CONFIG_CONFIGMAP_PERIOD:60}
     namespace: ${SW_CLUSTER_K8S_NAMESPACE:default}
diff --git a/oap-libs-for-graalvm/library-util-for-graalvm/pom.xml 
b/oap-libs-for-graalvm/library-util-for-graalvm/pom.xml
index bdc301c..ab03e5b 100644
--- a/oap-libs-for-graalvm/library-util-for-graalvm/pom.xml
+++ b/oap-libs-for-graalvm/library-util-for-graalvm/pom.xml
@@ -59,6 +59,8 @@
                             <excludes>
                                 
<exclude>org/apache/skywalking/oap/server/library/util/YamlConfigLoaderUtils.class</exclude>
                                 
<exclude>org/apache/skywalking/oap/server/library/util/ResourceUtils.class</exclude>
+                                
<exclude>org/apache/skywalking/oap/server/library/util/FieldsHelper.class</exclude>
+                                
<exclude>org/apache/skywalking/oap/server/library/util/FieldsHelper$*.class</exclude>
                             </excludes>
                         </filter>
                     </filters>
diff --git a/oap-libs-for-graalvm/pom.xml b/oap-libs-for-graalvm/pom.xml
index d20cb02..826a501 100644
--- a/oap-libs-for-graalvm/pom.xml
+++ b/oap-libs-for-graalvm/pom.xml
@@ -47,6 +47,7 @@
         <module>cilium-fetcher-for-graalvm</module>
         <module>status-query-for-graalvm</module>
         <module>health-checker-for-graalvm</module>
+        <module>server-starter-for-graalvm</module>
     </modules>
 
     <build>
diff --git a/oap-libs-for-graalvm/library-util-for-graalvm/pom.xml 
b/oap-libs-for-graalvm/server-starter-for-graalvm/pom.xml
similarity index 72%
copy from oap-libs-for-graalvm/library-util-for-graalvm/pom.xml
copy to oap-libs-for-graalvm/server-starter-for-graalvm/pom.xml
index bdc301c..02d013e 100644
--- a/oap-libs-for-graalvm/library-util-for-graalvm/pom.xml
+++ b/oap-libs-for-graalvm/server-starter-for-graalvm/pom.xml
@@ -27,18 +27,14 @@
         <version>1.0.0-SNAPSHOT</version>
     </parent>
 
-    <artifactId>library-util-for-graalvm</artifactId>
-    <name>Library Util for GraalVM</name>
-    <description>Repackaged library-util with GraalVM-compatible 
YamlConfigLoaderUtils</description>
+    <artifactId>server-starter-for-graalvm</artifactId>
+    <name>Server Starter for GraalVM</name>
+    <description>Repackaged server-starter with version.properties excluded 
(provided by oap-graalvm-server)</description>
 
     <dependencies>
         <dependency>
             <groupId>org.apache.skywalking</groupId>
-            <artifactId>library-util</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.projectlombok</groupId>
-            <artifactId>lombok</artifactId>
+            <artifactId>server-starter</artifactId>
         </dependency>
     </dependencies>
 
@@ -50,15 +46,14 @@
                 <configuration>
                     <artifactSet>
                         <includes>
-                            
<include>org.apache.skywalking:library-util</include>
+                            
<include>org.apache.skywalking:server-starter</include>
                         </includes>
                     </artifactSet>
                     <filters>
                         <filter>
-                            
<artifact>org.apache.skywalking:library-util</artifact>
+                            
<artifact>org.apache.skywalking:server-starter</artifact>
                             <excludes>
-                                
<exclude>org/apache/skywalking/oap/server/library/util/YamlConfigLoaderUtils.class</exclude>
-                                
<exclude>org/apache/skywalking/oap/server/library/util/ResourceUtils.class</exclude>
+                                <exclude>version.properties</exclude>
                             </excludes>
                         </filter>
                     </filters>
diff --git a/pom.xml b/pom.xml
index 2ec0877..9caf74d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -424,6 +424,11 @@
                 <artifactId>health-checker-for-graalvm</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.skywalking</groupId>
+                <artifactId>server-starter-for-graalvm</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.skywalking</groupId>
                 <artifactId>groovy-stubs</artifactId>


Reply via email to