提交 382fb89d 编写于 作者: Z ziyilin 提交者: dinglei

Graalvm expose an API for library file (#1167)

* [graal] Successfully run with main method

* [graal]Support build as a library
上级 8ab9aef0
#ifndef ROCKETMQ_H_
#define ROCKETMQ_H_
typedef struct Message_Send{
char* producer_name;
char* topic;
char* tags;
char* keys;
char* body;
}Message_Send_Struct;
#endif /* ROCKETMQ_H_ */
\ No newline at end of file
......@@ -33,6 +33,12 @@
</properties>
<dependencies>
<!-- svm.jar is required to be manually installed first -->
<dependency>
<groupId>com.oracle.substratevm</groupId>
<artifactId>svm</artifactId>
<version>1.0.0-rc16-dev</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>rocketmq-common</artifactId>
......
......@@ -3,19 +3,100 @@ Main entry for building native image
*/
package org.apache.rocketmq.client;
import java.util.Collections;
import java.util.List;
import org.apache.rocketmq.client.Producer.CRocketMQDirectives;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import com.alibaba.fastjson.parser.ParserConfig;
import org.graalvm.nativeimage.IsolateThread;
import org.graalvm.nativeimage.c.CContext;
import org.graalvm.nativeimage.c.function.CEntryPoint;
import org.graalvm.nativeimage.c.struct.CField;
import org.graalvm.nativeimage.c.struct.CStruct;
import org.graalvm.nativeimage.c.type.CCharPointer;
import org.graalvm.nativeimage.c.type.CTypeConversion;
import org.graalvm.word.PointerBase;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.logging.LogLevel;
import com.alibaba.fastjson.parser.ParserConfig;
import com.oracle.svm.core.c.ProjectHeaderFile;
/**
* @CContext annotation tells this class providing the context to interact with
* C context. This is required to build as a SO library file, but not necessary to
* build an executable file.
*
* @author cengfeng.lzy
*
*/
@CContext(CRocketMQDirectives.class)
public class Producer {
private static final LoggingHandler log = new LoggingHandler(LogLevel.DEBUG);
static class CRocketMQDirectives implements CContext.Directives {
@Override
public List<String> getHeaderFiles() {
/*
* The header file with the C declarations that are imported. Here we give the
* name of the header file. SVM searches the header file according to the file
* name specified here and the relative path specified in H:CLibraryPath in
* option.
*/
return Collections.singletonList(ProjectHeaderFile.resolve("client", "rocketMQ.h"));
}
}
/**
* This interface gives a Java version description of Message_Send_Struct data
* structure defined in the C header file.
*
* This declaration MUST be enclosed inside the @CContext class.
*
* @author cengfeng.lzy
*
*/
@CStruct("Message_Send_Struct")
interface CMessageSendStruct extends PointerBase {
@CField("producer_name")
CCharPointer getProducerName();
@CField("producer_name")
void setProducerName(CCharPointer value);
@CField("topic")
CCharPointer getTopic();
@CField("topic")
void setTopic(CCharPointer value);
@CField("tags")
CCharPointer getTags();
@CField("tags")
void setTags(CCharPointer value);
@CField("keys")
CCharPointer getKeys();
@CField("keys")
void setKeys(CCharPointer value);
@CField("body")
CCharPointer getBody();
@CField("body")
void setBody(CCharPointer value);
}
/**
* This main method is used to generate an executable file by SVM.
* @param args
* @throws MQClientException
* @throws InterruptedException
*/
public static void main(String[] args) throws MQClientException, InterruptedException {
ParserConfig.global.setAsmEnable(false);
DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
......@@ -24,9 +105,7 @@ public class Producer {
for (int i = 0; i < 128; i++)
try {
{
Message msg = new Message("TopicTest",
"TagA",
"OrderID188",
Message msg = new Message("TopicTest", "TagA", "OrderID188",
"Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult sendResult = producer.send(msg);
System.out.printf("%s%n", sendResult);
......@@ -38,4 +117,50 @@ public class Producer {
producer.shutdown();
}
/**
* This example shows how to expose an API with complex data structure
* parameter. This API wraps SendResult
* org.apache.rocketmq.client.producer.DefaultMQProducer.send(Message msg)
*
* @param thread isolated thread is required by SVM
* @param cmessageSends correspond to the Message_Send_Struct defined in the C
* header file.
* @return CCharPointer corresponds to char * in C
*/
@CEntryPoint(name = "send_message")
public static CCharPointer send(IsolateThread thread, CMessageSendStruct cmessageSends) {
// Disable dynamic class generation and class loading in Fastjson
ParserConfig.global.setAsmEnable(false);
DefaultMQProducer producer = new DefaultMQProducer(
// Here shows how to get a char * to String
CTypeConversion.toJavaString(cmessageSends.getProducerName()));
try {
producer.start();
} catch (MQClientException e1) {
e1.printStackTrace();
// Here shows how to convert null to char *.
// As the returned value must be of WordBase type, but null is of Object type.
// So we cannot return a null directly, but have to convert it to a
// CCharPointer.
return CTypeConversion.toCString(null).get();
}
String topic = CTypeConversion.toJavaString(cmessageSends.getTopic()); // TopicTest
String tags = CTypeConversion.toJavaString(cmessageSends.getTags()); // TagA
String key = CTypeConversion.toJavaString(cmessageSends.getKeys()); // OrderID188
String body = CTypeConversion.toJavaString(cmessageSends.getBody()); // Hello world
try {
// Construct a Message instance from the data extracted from C structure.
Message msg = new Message(topic, tags, key, body.getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult sendResult = producer.send(msg);
// Return string contents in SendResult instance.
return CTypeConversion.toCString(sendResult.toString()).get();
} catch (Exception e) {
e.printStackTrace();
return CTypeConversion.toCString(null).get();
} finally {
producer.shutdown();
}
}
}
......@@ -7,9 +7,7 @@ SVM_OPT="${SVM_OPT} --delay-class-initialization-to-runtime=io.netty.handler.ssl
SVM_OPT="${SVM_OPT} --delay-class-initialization-to-runtime=io.netty.handler.ssl.JdkAlpnSslEngine"
SVM_OPT="${SVM_OPT} --delay-class-initialization-to-runtime=io.netty.util.internal.JavassistTypeParameterMatcherGenerator"
SVM_OPT="${SVM_OPT} --delay-class-initialization-to-runtime=com.alibaba.fastjson.serializer.JodaCodec"
# testing
#SVM_OPT="${SVM_OPT} --delay-class-initialization-to-runtime=io.netty.handler.ssl.util.SelfSignedCertificate"
#SVM_OPT="${SVM_OPT} --delay-class-initialization-to-runtime=io.netty.handler.ssl.util.ThreadLocalInsecureRandom"
SVM_OPT="${SVM_OPT} --rerun-class-initialization-at-runtime=io.netty.handler.ssl.util.SelfSignedCertificate"
SVM_OPT="${SVM_OPT} --rerun-class-initialization-at-runtime=io.netty.handler.ssl.util.ThreadLocalInsecureRandom"
SVM_OPT="${SVM_OPT} --rerun-class-initialization-at-runtime=com.alibaba.fastjson.serializer.SerializeConfig"
......@@ -18,7 +16,16 @@ SVM_OPT="${SVM_OPT} --rerun-class-initialization-at-runtime=com.alibaba.fastjson
SVM_OPT="${SVM_OPT} --enable-url-protocols=http"
WORKDIR=`pwd`
CONFIG_OPT="-H:ConfigurationFileDirectories=${WORKDIR}/config -Dio.netty.noUnsafe=true -H:+ReportExceptionStackTraces --allow-incomplete-classpath"
native_image=/home/cengfeng.lzy/GraalDev/graal/vm/mxbuild/linux-amd64/GRAALVM_LIBGRAAL/graalvm-libgraal-1.0.0-rc16-dev/bin/native-image
#native_image=~/tools/graalvm-ce-1.0.0-rc14/bin/native-image
CONFIG_OPT="-H:ConfigurationFileDirectories=${WORKDIR}/config -H:+ReportExceptionStackTraces --allow-incomplete-classpath"
#Disable unsafe usage in netty. This option is provided by netty, not an univeral solution. A more general way
#is to use Graal's substition mechenism (see "Unsafe memory access" in
#https://medium.com/graalvm/instant-netty-startup-using-graalvm-native-image-generation-ed6f14ff7692)
CONFIG_OPT="${CONFIG_OPT} -Dio.netty.noUnsafe=true"
#Compile to a SO file
CONFIG_OPT="${CONFIG_OPT} --shared -H:Name=rocketMQClient"
#Specify where is the C library file which defines the data structure used in exposed API.
CONFIG_OPT="${CONFIG_OPT} -H:CLibraryPath=native"
#Set your own $native_image enviroment variable which should refer to the bin\native-image file in your graalvm JDK.
$native_image $CONFIG_OPT $SVM_OPT -jar target/rocketmq-client-4.5.1-SNAPSHOT-jar-with-dependencies.jar
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册