diff --git a/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/KafkaProcessor.java b/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/KafkaProcessor.java index b3c0cf71e205f..70c2cd59df207 100644 --- a/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/KafkaProcessor.java +++ b/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/KafkaProcessor.java @@ -75,18 +75,17 @@ import io.quarkus.deployment.builditem.IndexDependencyBuildItem; import io.quarkus.deployment.builditem.LaunchModeBuildItem; import io.quarkus.deployment.builditem.LogCategoryBuildItem; +import io.quarkus.deployment.builditem.NativeImageFeatureBuildItem; import io.quarkus.deployment.builditem.RunTimeConfigurationDefaultBuildItem; import io.quarkus.deployment.builditem.RuntimeConfigSetupCompleteBuildItem; import io.quarkus.deployment.builditem.nativeimage.NativeImageConfigBuildItem; import io.quarkus.deployment.builditem.nativeimage.NativeImageProxyDefinitionBuildItem; -import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem; import io.quarkus.deployment.builditem.nativeimage.NativeImageSecurityProviderBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassConditionBuildItem; import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem; import io.quarkus.deployment.logging.LogCleanupFilterBuildItem; import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem; -import io.quarkus.deployment.pkg.builditem.NativeImageRunnerBuildItem; import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild; import io.quarkus.kafka.client.runtime.KafkaAdminClient; import io.quarkus.kafka.client.runtime.KafkaBindingConverter; @@ -95,6 +94,7 @@ import io.quarkus.kafka.client.runtime.SnappyRecorder; import io.quarkus.kafka.client.runtime.devui.KafkaTopicClient; import io.quarkus.kafka.client.runtime.devui.KafkaUiUtils; +import io.quarkus.kafka.client.runtime.graal.SnappyFeature; import io.quarkus.kafka.client.serialization.BufferDeserializer; import io.quarkus.kafka.client.serialization.BufferSerializer; import io.quarkus.kafka.client.serialization.JsonArrayDeserializer; @@ -310,27 +310,14 @@ public void build( } @BuildStep(onlyIf = { HasSnappy.class, NativeOrNativeSourcesBuild.class }) - public void handleSnappyInNative(NativeImageRunnerBuildItem nativeImageRunner, - BuildProducer reflectiveClass, - BuildProducer nativeLibs) { + public void handleSnappyInNative(BuildProducer reflectiveClass, + BuildProducer feature) { reflectiveClass.produce(ReflectiveClassBuildItem.builder("org.xerial.snappy.SnappyInputStream", "org.xerial.snappy.SnappyOutputStream") .reason(getClass().getName() + " snappy support") .methods().fields().build()); - String root = "org/xerial/snappy/native/"; - // add linux64 native lib when targeting containers - if (nativeImageRunner.isContainerBuild()) { - String dir = "Linux/x86_64"; - String snappyNativeLibraryName = "libsnappyjava.so"; - String path = root + dir + "/" + snappyNativeLibraryName; - nativeLibs.produce(new NativeImageResourceBuildItem(path)); - } else { // otherwise the native lib of the platform this build runs on - String dir = SnappyUtils.getNativeLibFolderPathForCurrentOS(); - String snappyNativeLibraryName = System.mapLibraryName("snappyjava"); - String path = root + dir + "/" + snappyNativeLibraryName; - nativeLibs.produce(new NativeImageResourceBuildItem(path)); - } + feature.produce(new NativeImageFeatureBuildItem(SnappyFeature.class)); } @BuildStep(onlyIf = HasSnappy.class) diff --git a/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/SnappyUtils.java b/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/SnappyUtils.java deleted file mode 100644 index 35a9060e72073..0000000000000 --- a/extensions/kafka-client/deployment/src/main/java/io/quarkus/kafka/client/deployment/SnappyUtils.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.quarkus.kafka.client.deployment; - -import org.xerial.snappy.OSInfo; - -/** - * This class should only be used if Snappy is available on the classpath. - */ -public class SnappyUtils { - - private SnappyUtils() { - // Avoid direct instantiation - } - - public static String getNativeLibFolderPathForCurrentOS() { - return OSInfo.getNativeLibFolderPathForCurrentOS(); - } -} diff --git a/extensions/kafka-client/runtime/src/main/java/io/quarkus/kafka/client/runtime/graal/SnappyFeature.java b/extensions/kafka-client/runtime/src/main/java/io/quarkus/kafka/client/runtime/graal/SnappyFeature.java new file mode 100644 index 0000000000000..e335b8ccbac78 --- /dev/null +++ b/extensions/kafka-client/runtime/src/main/java/io/quarkus/kafka/client/runtime/graal/SnappyFeature.java @@ -0,0 +1,63 @@ +package io.quarkus.kafka.client.runtime.graal; + +import java.io.File; + +import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.hosted.RuntimeResourceAccess; +import org.xerial.snappy.OSInfo; + +public class SnappyFeature implements Feature { + + /** + * This method uses code from org.xerial.snappy.SnappyLoader#findNativeLibrary + * to load the Snappy native library. The original code is licensed under the + * Apache License, Version 2.0 and includes the following notice: + * + *
+     *--------------------------------------------------------------------------
+     *  Copyright 2011 Taro L. Saito
+     *
+     *  Licensed under the Apache License, Version 2.0 (the "License");
+     *  you may not use this file except in compliance with the License.
+     *  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     *  Unless required by applicable law or agreed to in writing, software
+     *  distributed under the License is distributed on an "AS IS" BASIS,
+     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     *  See the License for the specific language governing permissions and
+     *  limitations under the License.
+     *--------------------------------------------------------------------------
+     * 
+ */ + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + final String KEY_SNAPPY_LIB_PATH = "org.xerial.snappy.lib.path"; + final String KEY_SNAPPY_LIB_NAME = "org.xerial.snappy.lib.name"; + + // Try to load the library in org.xerial.snappy.lib.path */ + String snappyNativeLibraryPath = System.getProperty(KEY_SNAPPY_LIB_PATH); + String snappyNativeLibraryName = System.getProperty(KEY_SNAPPY_LIB_NAME); + + // Resolve the library file name with a suffix (e.g., dll, .so, etc.) + if (snappyNativeLibraryName == null) { + snappyNativeLibraryName = System.mapLibraryName("snappyjava"); + } + + if (snappyNativeLibraryPath != null) { + File nativeLib = new File(snappyNativeLibraryPath, snappyNativeLibraryName); + if (nativeLib.exists()) { + RuntimeResourceAccess.addResource(OSInfo.class.getModule(), + snappyNativeLibraryPath + "/" + snappyNativeLibraryName); + return; + } + } + + // Load an OS-dependent native library inside a jar file + snappyNativeLibraryPath = "org/xerial/snappy/native/" + OSInfo.getNativeLibFolderPathForCurrentOS(); + String path = snappyNativeLibraryPath + "/" + snappyNativeLibraryName; + RuntimeResourceAccess.addResource(OSInfo.class.getModule(), path); + } + +}