LuaJ

I was reading over the list of features that CurioDB lacks compared to Redis , that I’d previously documented. It contained the item “no Lua scripting”, which I’d written confidently at the time, certain that I wouldn’t possibly be able to implement something so serious in my toy project. But then I thought to myself, “why not?”, and after a bit of research, I discovered the fantastic LuaJ library , which transformed the task from a significant engineering feat, into yet another case of merely gluing some libraries together.

LuaJ provides a complete API for compiling and running Lua scripts, and exposing JVM code to them as Lua functions. LuaJ also makes a complete range of Lua data types available to your JVM code. I purposely refer to the JVM ( Java Virtual Machine ) here rather than Java the language, as in my case, it’s actually Scala being used to code against LuaJ, which makes the overall accomplishment seem even more death-defying.

Obligatory Blog Snippets

Let’s take a look. First up, we’ll compile and run a snippet of Lua (sans imports and class scaffolding, which you can pick up from the final result in CurioDB if you wish):

// The global namespace we'll run the script in, which we could preload
// variables into if needed. val globals = JsePlatform.standardGlobals() // A tiny string of Lua code - it returns the second string from a // table called "names" (Lua tables use 1-based indexes). val script = "names = {'foo', 'bar', 'baz'}; return names[2]" // Running the script returns a LuaValue object, which from our Lua // code above, we know to be a string, so we cast it to one and print // the value, which should be "bar". val result = globals.load(script).call() println(result.asjstring)

As simple as that. Now let’s look at passing Lua variables from JVM land into a Lua script, and pulling Lua variables back out as JVM objects:

// The same table declared above in Lua, but this time in Scala.
val names = LuaValue.listOf(Array("foo", "bar", "baz").map(LuaValue.valueOf))// Create the global namespace again, and pass the Lua table into it. val globals = JsePlatform.standardGlobals() globals.set("names", names) // Our Lua code is inline here, and just returns the variable "names". val result = globals.load("return names").call() // The result is our original table back in Scala, where we can access // items by index, just as we previously did in Lua. println(result.get(2).asjstring)

There you have it - JVM objects representing Lua variables, moving into and back out of Lua code. Now let’s look at the reverse, calling JVM code from inside Lua. To do this, we implement a class representing a Lua function:

// Simple function that takes a string, and prefixes it with "Hello ".
class SayHelloFunction extends OneArgFunction { override def call(name: LuaValue) = LuaValue.valueOf("Hello " + name.tojstring) } // Again, build the global namespace, this time adding the function // object to it with a given name, and calling it from within Lua. val globals = JsePlatform.standardGlobals() globals.set("say_hello", new SayHelloFunction()) val result = globals.load("return say_hello('grandma')").call() println(result.asjstring) // prints "Hello grandma".

That’s it, the full round trip - Lua calling JVM code, and vice versa. With that working, the rest is up to your imagination. I’ve only scratched the surface of what LuaJ provides - all of the data types found in Lua, its standard library, and much more.

The final result was a little more involved than the above implies. CurioDB is carefully designed to be non-blocking, using tell rather than ask , where actors only ever send messages forwards, without expectation of a reply. The challenge here was introducing the synchronous redis.call API into a fundamentally asynchronous system. The solution involved modelling the scripting API as a client actor, with a controlled amount of blocking, much like the way TCP and HTTP connections are managed in the system.

Call-ception

A really fun and whacky side effect of implementing this possibly a little too correctly(for lack of a better term), is that it unintentionally allows the Lua API to recursively call itself:

$ redis-cli EVAL "return redis.call('EVAL', 'return redis.call(\'EVAL\', \'return redis.call(\\\\\'TIME\\\\\')\', 0)', 0)" 0 1) (integer) 227734 2) (integer) 541653

Is this a feature, or a bug? The scripting API in Redis specifically disallows this, most likely for good reason.

http://www.tuicool.com/articles/M36byiy

http://stackoverflow.com/questions/32573748/multiple-return-values-in-luaj

http://levelup.sinaapp.com/

http://www.luaj.org/luaj/3.0/README.html

http://luaj.org/luaj/3.0/api/org/luaj/vm2/LuaValue.html

http://stackoverflow.com/questions/12358047/how-can-i-pass-objects-to-an-exposed-luaj-function

转载于:https://www.cnblogs.com/softidea/p/5285942.html

Embedding Lua, in Scala, using Java(转)相关推荐

  1. Scala与Java交互

    2019独角兽企业重金招聘Python工程师标准>>> ###代码示例 假如我们想要根据某个特定国家(比如法国)的习惯来获取并格式化当前日期, 我们可以使用以下 Scala 和 Ja ...

  2. Scala调用Java静态成员及静态方法注意点——只能通过当前类名调用而不能借助子类调用父类静态成员/方法

    只能通过当前类名NioUtil调用静态成员 package com.zxl.scalaimport cn.hutool.core.io.{FileUtil, IoUtil, NioUtil} impo ...

  3. 详解Scala与Java的互动

    详解Scala与Java的互动

  4. scala调用java代码_scala调用java代码

    scala调用java代码 @(SCALA)[scala] 在scala中调用java代替非常非常简单,直接调用即可 (一)一个简单示例 1.创建一个java类 package com.lujinho ...

  5. Scala与Java集合互转摘要

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

  6. 如何获取Kafka的消费者详情——从Scala到Java的切换

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

  7. scala调用java代码

    scala调用java代码 @(SCALA)[scala] 详细代码请见https://github.com/lujinhong/scalademo 在scala中调用java代替非常非常简单,直接调 ...

  8. Scala入门到精通——第二十八节 Scala与JAVA互操作

    本节主要内容 JAVA中调用Scala类 Scala中调用JAVA类 Scala类型参数与JAVA泛型互操作 Scala与Java间的异常处理互操作 1. JAVA中调用Scala类 Java可以直接 ...

  9. scala与java混合编译出现的问题

    工程项目中同时包含scala和java代码,如果在java中调用scala的类,编译时可能会报找不到scala类的错误,出现这种问题的解决办法是需要对scala进行先行编译,具体需要在pom文件中添加 ...

最新文章

  1. 服务器是什么系统_为什么视频监控系统搭建,要使用流媒体服务器做视频分发?...
  2. 在项目中使用 calendar_date_select
  3. SAP云平台,Netweaver,Kubernetes和C4C的用户和角色关系
  4. MariaDB基础(二)
  5. 多个折线样式_新技能get,折线图转化成多阶梯瀑布图
  6. 惩罚函数外点matlab,禁忌搜索算法求解带时间窗的车辆路径问题(惩罚函数版 附MATLAB代码)...
  7. python2.0 s12 day4
  8. 检测表单是否合法,为什么不能用n++的探讨
  9. quartus仿真17:T触发器的时序逻辑电路
  10. Pure Pursuit纯跟踪算法的Matlab算法实现
  11. Modscan和Modsim 两种Modbus调试工具使用说明
  12. SpringBoot实现人脸识别功能
  13. 资源 | 最新版区块链术语表(中英文对照)
  14. 二阶无源低通滤波器幅频特性曲线_一文看懂二阶lc低通滤波器的设计及原理
  15. python发邮件被认定为垃圾邮件_【python文本分类】20行代码识别垃圾邮件
  16. 学习计算机英语的重要性
  17. 代码审查工具rietveld的安装与使用(一)
  18. 无需安装软件架设NOD32升级服务器指南!
  19. 【mysql】大小写规范
  20. linux双线路由,双线机房双IP linux设置路由

热门文章

  1. mysql数据库引擎博客_2、MySQL常见数据库引擎及比较?
  2. vue判断浏览器是否id_QQ被曝读取浏览器历史记录!回应称系用于判断是否恶意登录...
  3. Java实用教程笔记 子类与继承
  4. matlab 图片转换
  5. 【Verilog HDL 训练】第 13 天(存储器、SRAM)
  6. JavaScript的使用
  7. Node 深入Stream(2)
  8. windows下php7.1安装redis扩展以及redis测试使用全过程
  9. jQuery的自定义动画
  10. HDU-3068-最长回文 (Manacher算法)