This is an automated email from the ASF dual-hosted git repository.
dinglei pushed a commit to branch graalvm
in repository https://gitbox.apache.org/repos/asf/rocketmq.git
The following commit(s) were added to refs/heads/graalvm by this push:
new 382fb89 Graalvm expose an API for library file (#1167)
382fb89 is described below
commit 382fb89d88f7057615c13496839941ac4bb17cbf
Author: ziyilin <lin.ziyi@hotmail.com>
AuthorDate: Fri Apr 19 16:05:16 2019 +0800
Graalvm expose an API for library file (#1167)
* [graal] Successfully run with main method
* [graal]Support build as a library
---
client/native/rocketMQ.h | 15 ++
client/pom.xml | 6 +
.../java/org/apache/rocketmq/client/Producer.java | 177 ++++++++++++++++++---
client/svm.sh | 19 ++-
4 files changed, 185 insertions(+), 32 deletions(-)
diff --git a/client/native/rocketMQ.h b/client/native/rocketMQ.h
new file mode 100644
index 0000000..51b363f
--- /dev/null
+++ b/client/native/rocketMQ.h
@@ -0,0 +1,15 @@
+#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
diff --git a/client/pom.xml b/client/pom.xml
index afa47c0..72c0454 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -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>
diff --git a/client/src/main/java/org/apache/rocketmq/client/Producer.java b/client/src/main/java/org/apache/rocketmq/client/Producer.java
index ff87cd6..5f7d0b8 100644
--- a/client/src/main/java/org/apache/rocketmq/client/Producer.java
+++ b/client/src/main/java/org/apache/rocketmq/client/Producer.java
@@ -3,39 +3,164 @@ 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);
- public static void main(String[] args) throws MQClientException, InterruptedException
{
- ParserConfig.global.setAsmEnable(false);
- DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
- producer.start();
-
- for (int i = 0; i < 128; i++)
- try {
- {
- Message msg = new Message("TopicTest",
- "TagA",
- "OrderID188",
- "Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
- SendResult sendResult = producer.send(msg);
- System.out.printf("%s%n", sendResult);
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- producer.shutdown();
- }
+ 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");
+ producer.start();
+
+ for (int i = 0; i < 128; i++)
+ try {
+ {
+ Message msg = new Message("TopicTest", "TagA", "OrderID188",
+ "Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
+ SendResult sendResult = producer.send(msg);
+ System.out.printf("%s%n", sendResult);
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ 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();
+ }
+ }
}
diff --git a/client/svm.sh b/client/svm.sh
index e13cfcf..b56062d 100755
--- a/client/svm.sh
+++ b/client/svm.sh
@@ -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
|