
I recently encountered such a problem and was extremely surprised that there are very few materials on the network, given the popularity of Lua. As it turned out, there are quite a lot of libraries for working with Lua scripts from java, but they all have their own nuances. Best of all, as it turned out, use the
LuaJava library from the same developers that wrote Lua.
Build LuaJava Library
At once I will say that it is better to unpack the archive with the input files and perform the assembly in a special folder, from where you will connect the assembled jar-file to the project. The path to this folder will also need to be registered in ClassPath. If you compile the jar-archive, and then copy it into the folder with the java-project, the program will not start just like that. But this will be lower.
The manual’s page says that happy Linux and OSX users can build a library from source with a simple make command, making minor changes to the config file, config. Initially this file looks like this.
#############################################################
#Linux/BSD/Mac
LUA_DIR= /usr/local/share/lua/5.1.1
LUA_LIBDIR= /usr/local/lib
LUA_INCLUDES= /usr/local/include
JDK= $(JAVA_HOME)
# For Mac OS, comment the above line and uncomment this one
#JDK=/Library/Java/Home
# Full path to Lua static library
LIB_LUA=$(LUA_LIBDIR)/liblua.a
#Linux/BSD
LIB_EXT= .so
#Mac OS
#LIB_EXT= .jnilib
LIB_PREFIX= lib
#Linux/BSD
LIB_OPTION= -shared
#Mac OS
#LIB_OPTION= -dynamiclib -all_load
## On FreeBSD and Mac OS systems, the following line should be commented
DLLIB= -ldl
WARN= -O2 -Wall -fPIC -W -Waggregate-return -Wcast-align -Wmissing-prototypes -Wnested-externs -Wshadow -Wwrite-strings
INCS= -I$(JDK)/include -I$(JDK)/include/linux -I$(LUA_INCLUDES)
CFLAGS= $(WARN) $(INCS)
CC= gcc
#########################################################
VERSION= 1.1
PKG= luajava-$(VERSION)
TAR_FILE= $(PKG).tar.gz
ZIP_FILE= $(PKG).zip
JAR_FILE= $(PKG).jar
SO_FILE= $(LIB_PREFIX)$(PKG)$(LIB_EXT)
DIST_DIR= $(PKG)
# $Id: config,v 1.12 2006/12/22 14:06:40 thiago Exp $
If you immediately try to do make, then nothing good will happen. Here is what you need to do to successfully assemble the library:
1. Either create the JAVA_HOME environment variable, or set it in the configuration file, specifying the path to the folder where java is installed. I added this variable the first line in the configuration file:
JAVA_HOME= /usr/lib/jvm/java-6-sun-1.6.0.26
2. Download Lua binary files
from here . We need the Linux archive ### _ lib.tar.gz. After unpacking the archive, the files liblua5.1a and liblua5.1.so need to be copied to the / usr / local / lib folder, and the files from the include folder to the / usr / local / include folder. After that, in the configuration file, replace the line
LIB_LUA=$(LUA_LIBDIR)/liblua.a
on
LIB_LUA=$(LUA_LIBDIR)/liblua5.1.a
3. Gcc must also be installed.
Everything, now it is possible to collect library. After the make command, 2 files appear: luajava-1.1.jar and libluajava-1.1.so. The manual says that .jar needs to be placed in the lib / folder with your project, and the .so file is either in the JRE bin / folder or in the folder where the variable LD_LIBRARY_PATH points to. I put this file in the bin / jre folder.
Java project configuration
In the java project, you need to connect the external library luajava-1.1.jar. Also, running a little ahead, you need to add a string in the VM arguments
-Djava.library.path=[ , LuaJava]
Now you can safely write Lua-scripts and access them from the program. This is done using the org.keplerproject.luajava.LuaState class. I came across
an example in which a special class was written to call the Lua functions. Here is an example of a class that I use:
')
import org.keplerproject.luajava.LuaObject; import org.keplerproject.luajava.LuaState; import org.keplerproject.luajava.LuaStateFactory; public class LuaScriptLoader { private LuaState luaState; public LuaScriptLoader(String fileFullName) { luaState = LuaStateFactory.newLuaState(); luaState.openLibs(); luaState.LdoFile(fileFullName); } public void closeScript() { luaState.close(); } public String getRoomDescription() { luaState.getGlobal("getRoomDescription"); luaState.call(0, 1); LuaObject lo = luaState.getLuaObject(1); luaState.pop(1); return lo.getString(); } public void runScriptFunction(String functionName, LuaAdapter adapter) { luaState.getGlobal(functionName); luaState.pushJavaObject(adapter); luaState.call(1, 0); } }
The program will run from the programming environment. If you want to launch a .jar file with your program, you need to do 2 things:
1. When exporting, use a manifest file in which the Class-Path attribute should be specified
Class-Path: [ , LuaJava]/luajava-1.1.jar
2. Run the .jar file with the same key that is specified in the VM arguments of the environment
-Djava.library.path=[ , LuaJava]
When the call method of class LuaState is accessed, 2 integer parameters are passed. This is the number of arguments and the number of return values. In the getRoomDescription () method you can see how to get the result from the Lua function (0 arguments, 1 return value), and in the runScriptFunction () method, how to pass java-objects to the script (1 argument, 0 return values). The LuaAdapter class is my class that has several public methods. These methods can be called from a script. Here is an example of a file with a script:
function getRoomDescription() return "" end function processMessage(adapter) local message = adapter:getMessage() local user = adapter:getUser() local nick = user:getNick() adapter:sendMessageToRoomAndUser(user, nick..": "..message, "") end function userEnter(adapter) local user = adapter:getUser() local nick = user:getNick() adapter:sendMessageToRoomAndUser(user, " "..nick, " ") end function userLeft(adapter) local nick = adapter:getUser():getNick() adapter:sendMessageToRoom(" "..nick.." ") end
In this example, a conference room is scripted using Lua, where users can communicate. All public methods that are in the LuaAdapter class are successfully called and executed.
UPD: forgot one more thing. You can work with java-classes and objects from Lua not only as I described above (passing the object as a parameter to the Lua-function). In the
manual LuaJava described several more ways. I worked with the first two, they worked without any problems, I did not try the others as superfluous. I will describe the first two ways:
1. Call the newInstance (className, ...) function of the LuaJava library. The first parameter of the function is the full name of the java-class, the rest are the parameters of the constructor. The result of calling this function will be a new java-object with which you can work.
Example:
obj = luajava.newInstance("java.lang.Object")
You can also call your classes by passing their names as parameters (for example, “myproject.mypackage.MyClass”). But here there are nuances that I have not met:
- it is not clear to which project the Lua script has access. I doubt that to all
- if you have access to many projects, or you can call Lua scripts from several projects, and in these projects there are classes with the same name, then it is not clear which class object will be created
2. Call the bindClass (className) function of the LuaJava library. This function will return an object for which it will be possible to access the static fields and methods of the java-class whose name has been specified.
Example:
sys = luajava.bindClass("java.lang.System") print ( sys:currentTimeMillis() )
You can also call your classes (with the same nuances).
I called these Lua-functions only from one project, and in functions I addressed classes only of this project, therefore I did not encounter any problems
UPD Found a nuance. The call method does not know how to catch errors that may be present in the script. If there is an error in the script, the whole program crashes. Iksepshenov this method does not throw. The only solution that nagulit - is to try to run a script call from another thread. But it is very ugly. But the LuaState class has a pcall method:
public int pcall(int nArgs, int nResults, int errFunc)
which in the case of a successful call will return the value 0, and a non-zero value as a result of an unsuccessful call. The first two arguments repeat the arguments of the call method, the last parameter apparently should point to the error handling function. In this case, the error description will be saved in the LuaState object with which the script function was called. Now the runScriptFunction method looks like this for me:
public void runScriptFunction(String functionName, LuaAdapter adapter) { luaState.getGlobal(functionName); luaState.pushJavaObject(adapter); int res = luaState.pcall(1, 0, 0); if(res != 0) { Main.log(Level.SEVERE, "LuaScriptLoader call error: " + luaState.toString(-1)); } } }