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 <[email protected]>
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

Reply via email to