Skip to content
This repository has been archived by the owner on Sep 26, 2023. It is now read-only.

Commit

Permalink
feat: relocate Netty Native Image configurations from java-core to gax (
Browse files Browse the repository at this point in the history
#1638)

* feat: relocate Netty Native Image configurations from java-core to gax
  • Loading branch information
mpeddada1 committed Mar 31, 2022
1 parent 2264c39 commit aafded4
Show file tree
Hide file tree
Showing 7 changed files with 284 additions and 2 deletions.
2 changes: 2 additions & 0 deletions dependencies.properties
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ maven.com_google_http_client_google_http_client=com.google.http-client:google-ht
maven.com_google_http_client_google_http_client_gson=com.google.http-client:google-http-client-gson:1.41.5
maven.org_codehaus_mojo_animal_sniffer_annotations=org.codehaus.mojo:animal-sniffer-annotations:1.18
maven.javax_annotation_javax_annotation_api=javax.annotation:javax.annotation-api:1.3.2
maven.org_graalvm_nativeimage_svm=org.graalvm.nativeimage:svm:22.0.0.2
maven.org_graalvm_sdk=org.graalvm.sdk:graal-sdk:22.0.0.2

# Testing maven artifacts
maven.junit_junit=junit:junit:4.13.2
Expand Down
2 changes: 2 additions & 0 deletions gax-grpc/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ _COMPILE_DEPS = [
"@io_netty_netty_tcnative_boringssl_static//jar",
"@javax_annotation_javax_annotation_api//jar",
"//gax:gax",
"@org_graalvm_nativeimage_svm//jar",
"@org_graalvm_sdk//jar"
]

_TEST_COMPILE_DEPS = [
Expand Down
4 changes: 3 additions & 1 deletion gax-grpc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ dependencies {

runtimeOnly libraries['maven.io_grpc_grpc_xds']

compileOnly libraries['maven.com_google_auto_value_auto_value']
compileOnly(libraries['maven.com_google_auto_value_auto_value'],
libraries['maven.org_graalvm_sdk'],
libraries['maven.org_graalvm_nativeimage_svm'])

testImplementation( project(':gax').sourceSets.test.output,
libraries['maven.junit_junit'],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* Copyright 2022 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.google.api.gax.grpc.nativeimage;

import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassForReflection;
import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassHierarchyForReflection;
import static com.google.api.gax.nativeimage.NativeImageUtils.registerForReflectiveInstantiation;
import static com.google.api.gax.nativeimage.NativeImageUtils.registerForUnsafeFieldAccess;

import com.oracle.svm.core.annotate.AutomaticFeature;
import org.graalvm.nativeimage.hosted.Feature;

/** Configures Native Image settings for the grpc-netty-shaded dependency. */
@AutomaticFeature
final class GrpcNettyFeature implements Feature {

private static final String GRPC_NETTY_SHADED_CLASS =
"io.grpc.netty.shaded.io.grpc.netty.NettyServer";

private static final String GOOGLE_AUTH_CLASS =
"com.google.auth.oauth2.ServiceAccountCredentials";

private static final String NETTY_SHADED_PACKAGE =
"io.grpc.netty.shaded.io.netty.util.internal.shaded.";

@Override
public void beforeAnalysis(BeforeAnalysisAccess access) {
loadGoogleAuthClasses(access);
loadGrpcNettyClasses(access);
loadMiscClasses(access);
}

private static void loadGoogleAuthClasses(BeforeAnalysisAccess access) {
// For com.google.auth:google-auth-library-oauth2-http
Class<?> authClass = access.findClassByName(GOOGLE_AUTH_CLASS);
if (authClass != null) {
registerClassHierarchyForReflection(access, GOOGLE_AUTH_CLASS);
registerClassHierarchyForReflection(
access, "com.google.auth.oauth2.ServiceAccountJwtAccessCredentials");
}
}

private static void loadGrpcNettyClasses(BeforeAnalysisAccess access) {
// For io.grpc:grpc-netty-shaded
Class<?> nettyShadedClass = access.findClassByName(GRPC_NETTY_SHADED_CLASS);
if (nettyShadedClass != null) {
// Misc. classes used by grpc-netty-shaded
registerForReflectiveInstantiation(
access, "io.grpc.netty.shaded.io.netty.channel.socket.nio.NioSocketChannel");
registerClassForReflection(
access, "io.grpc.netty.shaded.io.netty.util.internal.NativeLibraryUtil");
registerClassForReflection(access, "io.grpc.netty.shaded.io.netty.util.ReferenceCountUtil");
registerClassForReflection(
access, "io.grpc.netty.shaded.io.netty.buffer.AbstractByteBufAllocator");

// Epoll Libraries
registerClassForReflection(access, "io.grpc.netty.shaded.io.netty.channel.epoll.Epoll");
registerClassForReflection(
access, "io.grpc.netty.shaded.io.netty.channel.epoll.EpollChannelOption");
registerClassForReflection(
access, "io.grpc.netty.shaded.io.netty.channel.epoll.EpollEventLoopGroup");
registerForReflectiveInstantiation(
access, "io.grpc.netty.shaded.io.netty.channel.epoll.EpollServerSocketChannel");
registerForReflectiveInstantiation(
access, "io.grpc.netty.shaded.io.netty.channel.epoll.EpollSocketChannel");

// Unsafe field accesses
registerForUnsafeFieldAccess(
access,
NETTY_SHADED_PACKAGE + "org.jctools.queues.MpscArrayQueueProducerIndexField",
"producerIndex");
registerForUnsafeFieldAccess(
access,
NETTY_SHADED_PACKAGE + "org.jctools.queues.MpscArrayQueueProducerLimitField",
"producerLimit");
registerForUnsafeFieldAccess(
access,
NETTY_SHADED_PACKAGE + "org.jctools.queues.MpscArrayQueueConsumerIndexField",
"consumerIndex");
registerForUnsafeFieldAccess(
access,
NETTY_SHADED_PACKAGE + "org.jctools.queues.BaseMpscLinkedArrayQueueProducerFields",
"producerIndex");
registerForUnsafeFieldAccess(
access,
NETTY_SHADED_PACKAGE + "org.jctools.queues.BaseMpscLinkedArrayQueueColdProducerFields",
"producerLimit");
registerForUnsafeFieldAccess(
access,
NETTY_SHADED_PACKAGE + "org.jctools.queues.BaseMpscLinkedArrayQueueConsumerFields",
"consumerIndex");
}
}

/** Miscellaneous classes that need to be registered coming from various JARs. */
private static void loadMiscClasses(BeforeAnalysisAccess access) {
registerClassHierarchyForReflection(access, "com.google.protobuf.DescriptorProtos");
registerClassForReflection(access, "com.google.api.FieldBehavior");

registerForUnsafeFieldAccess(access, "javax.net.ssl.SSLContext", "contextSpi");
registerClassForReflection(access, "java.lang.management.ManagementFactory");
registerClassForReflection(access, "java.lang.management.RuntimeMXBean");
}
}
2 changes: 2 additions & 0 deletions gax/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ _COMPILE_DEPS = [
"@com_google_code_gson_gson//jar",
"@com_google_guava_failureaccess//jar",
"@javax_annotation_javax_annotation_api//jar",
"@org_graalvm_nativeimage_svm//jar",
"@org_graalvm_sdk//jar"
]

_TEST_COMPILE_DEPS = [
Expand Down
4 changes: 3 additions & 1 deletion gax/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ dependencies {
libraries['maven.com_google_guava_guava'],
libraries['maven.io_opencensus_opencensus_api'])

compileOnly libraries['maven.com_google_auto_value_auto_value']
compileOnly(libraries['maven.com_google_auto_value_auto_value'],
libraries['maven.org_graalvm_sdk'],
libraries['maven.org_graalvm_nativeimage_svm'])

testImplementation(libraries['maven.junit_junit'],
libraries['maven.org_mockito_mockito_core'],
Expand Down
140 changes: 140 additions & 0 deletions gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* Copyright 2022 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.google.api.gax.nativeimage;

import com.google.api.core.InternalApi;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.graalvm.nativeimage.hosted.Feature.FeatureAccess;
import org.graalvm.nativeimage.hosted.RuntimeReflection;

/** Internal class offering helper methods for registering methods/classes for reflection. */
@InternalApi
public class NativeImageUtils {

private static final Logger LOGGER = Logger.getLogger(NativeImageUtils.class.getName());
private static final String CLASS_REFLECTION_ERROR_MESSAGE =
"Failed to find {0} on the classpath for reflection.";

private NativeImageUtils() {}

/** Returns the method of a class or fails if it is not present. */
public static Method getMethodOrFail(Class<?> clazz, String methodName, Class<?>... params) {
try {
return clazz.getDeclaredMethod(methodName, params);
} catch (NoSuchMethodException e) {
throw new IllegalStateException(
String.format("Failed to find method %s for class %s", methodName, clazz.getName()), e);
}
}

/** Registers a class for reflective construction via its default constructor. */
public static void registerForReflectiveInstantiation(FeatureAccess access, String className) {
Class<?> clazz = access.findClassByName(className);
if (clazz != null) {
RuntimeReflection.register(clazz);
RuntimeReflection.registerForReflectiveInstantiation(clazz);
} else {
LOGGER.log(
Level.WARNING,
"Failed to find {0} on the classpath for reflective instantiation.",
className);
}
}

/** Registers all constructors of a class for reflection. */
public static void registerConstructorsForReflection(FeatureAccess access, String name) {
Class<?> clazz = access.findClassByName(name);
if (clazz != null) {
RuntimeReflection.register(clazz);
RuntimeReflection.register(clazz.getDeclaredConstructors());
} else {
LOGGER.log(Level.WARNING, CLASS_REFLECTION_ERROR_MESSAGE, name);
}
}

/** Registers an entire class for reflection use. */
public static void registerClassForReflection(FeatureAccess access, String name) {
Class<?> clazz = access.findClassByName(name);
if (clazz != null) {
RuntimeReflection.register(clazz);
RuntimeReflection.register(clazz.getDeclaredConstructors());
RuntimeReflection.register(clazz.getDeclaredFields());
RuntimeReflection.register(clazz.getDeclaredMethods());
} else {
LOGGER.log(Level.WARNING, CLASS_REFLECTION_ERROR_MESSAGE, name);
}
}

/**
* Registers the transitive class hierarchy of the provided {@code className} for reflection.
*
* <p>The transitive class hierarchy contains the class itself and its transitive set of
* *non-private* nested subclasses.
*/
public static void registerClassHierarchyForReflection(FeatureAccess access, String className) {
Class<?> clazz = access.findClassByName(className);
if (clazz != null) {
registerClassForReflection(access, className);
for (Class<?> nestedClass : clazz.getDeclaredClasses()) {
if (!Modifier.isPrivate(nestedClass.getModifiers())) {
registerClassHierarchyForReflection(access, nestedClass.getName());
}
}
} else {
LOGGER.log(Level.WARNING, CLASS_REFLECTION_ERROR_MESSAGE, className);
}
}

/** Registers a class for unsafe reflective field access. */
public static void registerForUnsafeFieldAccess(
FeatureAccess access, String className, String... fields) {
Class<?> clazz = access.findClassByName(className);
if (clazz != null) {
RuntimeReflection.register(clazz);
for (String fieldName : fields) {
try {
RuntimeReflection.register(clazz.getDeclaredField(fieldName));
} catch (NoSuchFieldException ex) {
LOGGER.warning("Failed to register field " + fieldName + " for class " + className);
LOGGER.warning(ex.getMessage());
}
}
} else {
LOGGER.log(
Level.WARNING,
"Failed to find {0} on the classpath for unsafe fields access registration.",
className);
}
}
}

0 comments on commit aafded4

Please sign in to comment.