Passing arguments to a lua function with luaj - java

I'm trying to call a lua function in a Java program using LuaJ. It works fine when I'm not passing any arguments to the closure:
String script = "print 'Hello World!'";
InputStream input = new ByteArrayInputStream(script.getBytes());
Prototype prototype = LuaC.compile(input, "script");
LuaValue globals = JsePlatform.standardGlobals();
LuaClosure closure = new LuaClosure(prototype, globals);
closure.call();
But now I'm trying a lua script with a top-level function that takes an argument and I just can't figure out how to pass in the argument from Java. Here's what I got so far:
String script = "function something(argument)\n"+
"test_string = 'Hello World!'\n"+
"print(test_string)\n"+
"print(argument)\n"+
"end";
InputStream input = new ByteArrayInputStream(script.getBytes());
Prototype prototype = LuaC.compile(input, "script");
LuaValue globals = JsePlatform.standardGlobals();
LuaClosure closure = new LuaClosure(prototype, globals);
closure.invokemethod("something", CoerceJavaToLua.coerce("Foo"));
This results in an Exception on the invokemethod line:
org.luaj.vm2.LuaError: attempt to index ? (a function value)
Thanks for your help!

In lua, the top-level scope is an anonymous function with variable arguments. These are accessed using ... In your example, you don't need the function named something, the chunk itself can be used as an unnamed function.
For example, this code in luaj-3.0-beta1
String script = "argument = ...\n"+
"test_string = 'Hello World!'\n"+
"print(test_string)\n"+
"print(argument)\n";
Globals globals = JsePlatform.standardGlobals();
LuaValue chunk = globals.loadString(script, "myscript");
chunk.call( LuaValue.valueOf("some-arg-value") );
Produced this result for me:
Hello World!
some-arg-value
You can pass in any number of arguments this way.

Since you receive
org.luaj.vm2.LuaError: attempt to index ? (a function value)
as your error; this means that your function is not being created at all.
Try it without \n and give spaces in the variable script. Like this:
String script = "function something(argument) " +
" test_string = 'Hello World!'; " +
" print( test_string ); " +
" print( argument ); " +
" end";

Related

Java runtime exec not handling string array well

I have a tomcat servlet which calls a jar function with parameters. The first parameter sometimes contains space. So I tried to use a String array, but it doesn't work at all.
What am I doing wrong?
requestParm = "java -classpath c:\\j\\test.jar test.connect " + fileName + " new";
requestParmarray =new String[]{"java -classpath c:\\j\\test.jar test.connect ",fileName , " new"};
requestParmarrayNew =new String[]{"java -classpath c:\\j\\test.jar test.connect "+fileName+" new"};
// This line works.but can not handle space well
Process ls_proc = Runtime.getRuntime().exec(requestPar);
// Does not call the function at all
Process ls_proc = Runtime.getRuntime().exec(requestParmarray );
// Does not call the function at all
Process ls_proc = Runtime.getRuntime().exec(requestParmarrayNew );
// Does not call the function at all
Process ls_proc = new ProcessBuilder("java -classpath c:\\j\\test.jar test.connect ",fileName, "new" ).start();
You're creating the array incorrectly: Each individual argument must be in its own entry:
String[] requestParmArray = new String[] {
"java",
"-classpath",
"c:\\j\\test.jar",
"test.connect",
fileName,
"new"
};
Process ls_proc = Runtime.getRuntime().exec(requestParmArray);
Also note that I removed the space you had after test.connect; the spaces you put on the command line are just to separate arguments, but in the above, they're separated by being separate entries in the array.
You should make the array in exec() have each parameter as a separate array entry like:
String[] requestPar = new String[]{"java", "-classpath", "c:\\j\\test.jar", "test.connect ", fileName, "new"};
And use it:
Process ls_proc = Runtime.getRuntime().exec(requestPar);

LUAJ Coerced Java object won't accept LuaValue argument

I've come across an issue with LuaJ not accepting an LuaValue as an argument when the Java code specifically asks for an LuaValue.
public void registerEvent(LuaValue id, String event, String priority,
LuaValue callback)
{
if(!(id instanceof LuaTable))
{
throw new RuntimeException("id must be an LuaTable");
}
EventDispatcher.addHandler(id, event, priority, callback);
}
Ideally, this would allow the code in Lua to simply read like so...
function main(this)
this.modName="Some Mod"
this.lastX = 0
hg.both.registerEvent(this, "inputcapturedevent", "last", eventRun)
end
function eventRun(this, event)
this.lastX += event.getX()
end
Sadly, this simple gives an error that it expects userdata, but got a table.
org.luaj.vm2.LuaError: script:4 bad argument: userdata expected, got table
The value of "this" is the same LuaTable in both cases, but because the method registerEvent is added via CoerceJavaToLua.coerce(...) it believes it wants a java Object instead of realising it really wants an LuaVale.
So my question is this. Is there a better way around this that allows me to use the same function from both Java and Lua? And thanks for your time if you read it all the way here :)
The error you are getting is probably a red herring and may be due to the way you are binding the "registerEvent" function into the value of "hg.both". Possibly you just need to use the method syntax instead, such as
hg.both:registerEvent(this, "inputcapturedevent", "last", eventRun)
If you want to use the dot syntax hg.both.registerEvent, then using VarArgFunction and implementing invoke() may be a more direct way to implement this. In this example, Both.registerEvent is a plain variable that is a VarArgFunction.
public static class Both {
public static VarArgFunction registerEvent = new VarArgFunction() {
public Varargs invoke(Varargs args) {
LuaTable id = args.checktable(1);
String event = args.tojstring(2);
String priority = args.tojstring(3);
LuaValue callback = args.arg(4);
EventDispatcher.addHandler(id, event, priority, callback);
return NIL;
}
};
}
public static void main(String[] args) throws ScriptException {
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine engine = sem.getEngineByName("luaj");
Bindings sb = engine.createBindings();
String fr =
"function main(this);" +
" this.modName='Some Mod';" +
" this.lastX = 0;" +
" hg.both.registerEvent(this, 'inputcapturedevent', 'last', eventRun);" +
"end;";
System.out.println(fr);
CompiledScript script = ((Compilable) engine).compile(fr);
script.eval(sb);
LuaFunction mainFunc = (LuaFunction) sb.get("main");
LuaTable hg = new LuaTable();
hg.set("both", CoerceJavaToLua.coerce(Both.class));
sb.put("hg", hg);
LuaTable library = new LuaTable();
mainFunc.call(CoerceJavaToLua.coerce(library));
}

JT400 ProgramCall's run() method is not returning any result

I am new to JT400. I am trying to invoke a test program in AS400 through JT400. Here is my code
public class TestRpg {
public static void main(String[] args){
try{
AS400 sys=new AS400("mydomain","username","password");
String number="asdf <= Return value from Java Input";
String lnsts="";
String amount="";
String lnofcd="";
AS400Text txt80 = new AS400Text(80);
AS400Text txt50 = new AS400Text(50);
ProgramParameter[] parmList = new ProgramParameter[4];
parmList[0] = new ProgramParameter( txt80.toBytes(number),80);
parmList[1] = new ProgramParameter( txt50.toBytes(lnsts),50);
parmList[2] = new ProgramParameter( txt80.toBytes(amount),80);
parmList[3] = new ProgramParameter( txt50.toBytes(lnofcd),50);
ProgramCall pgm = new ProgramCall(sys,"/QSYS.LIB/mylib.LIB/testrpg.PGM",parmList);
if (pgm.run()!=true) {
System.out.println("executed");
}else{
System.out.println("Output Data 0: " + (String)txt80.toObject( parmList[0].getOutputData() ) );
System.out.println("Output Data 1: " + (String)txt50.toObject( parmList[1].getOutputData() ) );
System.out.println("Output Data 2: " + (String)txt80.toObject( parmList[2].getOutputData() ) );
System.out.println("Output Data 3: " + (String)txt50.toObject( parmList[3].getOutputData() ) );
sys.disconnectService(AS400.COMMAND);
}
AS400Message[] messageList = pgm.getMessageList();
System.out.println(messageList.length);
for (int i=0; i < messageList.length; i++)
{
System.out.print ( messageList[i].getID() );
System.out.print ( ": " );
System.out.println( messageList[i].getText() );
}
sys.disconnectService(AS400.COMMAND);
}catch(Exception e) {
System.out.println(e.toString());
}
}
}
I had debug the code it's not giving any response after executing
pgm.run(). It is not even showing any exception. Programme is just holding at pgm.run() and not returning any thing.
As per the comments I got, I want to include the scenario I am trying to work on. In AS400 when we execute the testrpg.pgm program, it displays a screen with four input fields and some function keys to perform operations. My intention is to invoke f2 function key of that program from JT400. Is the approach I am following is the right way? Please suggest me
All program calls happen in batch so your program is most likely in MSGW on the server. Find it with wrkactjob and investigate the message it is waiting for, and give the appropriate action.
This is typically due to incorrectly formed parameters.
This is a common misunderstanding, so just for clarification for other readers:
Calling a Cobol/RPG program from Java is batch, just the same as calling the Cobol/RPG program from a Cobol/RPG/CL.
How to begin: Create a program which you can call from CL:
... declare and fill MYFIELD1, MYFIELD2 ...
CALL PGM(MYPGM) PARM(&MYFIELD1 &MYFIELD2)
...
If this works, it will also work from Java using jt400, if you:
call the right AS400 using correct credentials
call the right program in the right library
use the right number and lentgh of parameters
In case of crash as described (waiting forever), DSPMSG QSYSOPR will show an open message, like "MCH0801 = wrong number of parameters". D=Dump will create a spoolfile where you see which incoming parameters are filled with which content, or you see "undefined".

Scala - Fails to execute a process through terminal in a particular scenario

I'm using graphviz to generate graphs based on the messages passed in a scala program.
To invoke the graphviz application from inside the scala program, I'm using the exec() method (similar to Java). It successfully executed the command and created the graph when I used the below code snippet:
var cmd: String = "dot -Tpng Graph.dot -o Graph.png"
var run: Runtime = Runtime.getRuntime() ;
var pr: Process = run.exec(cmd) ;
However It fails to execute after changing the path of the input and output files (I just included a directory inside which the input file and output file resides as shown below)
def main(args: Array[String]): Unit = {
var DirectoryName: String = "Logs"
var GraphFileName: String = DirectoryName + File.separator + "Graph.dot"
val GraphFileObj: File = new File(GraphFileName)
// var cmd: String = "dot -Tpng Graph.dot -o Graph.png"
var cmd: String = "dot -Tpng \"" + GraphFileObj.getAbsolutePath + "\" -o \"" + DirectoryName + File.separator + "Graph.png\"" ;
println(cmd)
var run: Runtime = Runtime.getRuntime() ;
var pr: Process = run.exec(cmd) ;
}
The same command when executed through terminal gives proper output. Can you please help me to find what I'm missing?
exec is not a shell...e.g. quoting won't work as you expect, and thus your path (which may contain spaces, etc) will not be processed as you expect. The command will be broken apart using StringTokenizer, and your literal quotes will be...well..literal.
Use the form of exec that takes an array instead, so you can tokenize the command correctly.
val args = Array[String]("dot", "-Tpng", GraphFileObj.getAbsolutePath, ...);
run.exec(args)

Getting output parameter value set by VBScript (WMI) method in java via JACOB

Am trying to convert a VBScript to java using JACOB - Java COM bridge library.
'Create' method in VBScript accepts a [out] param in it's method and it sets it upon method execution and i couldn't figure out how to retrieve it back via JACOB.
VBScript in question:
Function CreateProcess(strComputer, strCommand)
Dim objWMIService, objProcess
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set objProcess = objWMIService.Get("Win32_Process")
errReturn = objProcess.Create (strCommand, Null, Null, intProcessID)
Set objWMIService = Nothing
Set objProcess = Nothing
CreateProcess = intProcessID
End Function
intProcessID is [out] param set after method execution. (Create API contract)
Converted java code(incomplete and modified slightly for demonstration):
public static void createProcess() {
String host = "localhost";
String connectStr = String
.format("winmgmts:{impersonationLevel=impersonate}!\\\\%s\\root\\CIMV2",
host);
ActiveXComponent axWMI = new ActiveXComponent(connectStr);
Variant vCollection = axWMI.invoke("get", new Variant("Win32_Process"));
Dispatch d = vCollection.toDispatch();
Integer processId = null;
int result = Dispatch.call(d, "Create", "notepad.exe", null, null, processId)
.toInt();
System.out.println("Result:" + result);
// WORKS FINE until here i.e. notepad launches properly, however processId still seems to be null. Following commented code is wrong - doesn't work
//Variant v = Dispatch.get(d, "processId"); // even ProcessId doesn't work
//int pId = v.getInt();
//System.out.println("process id:"
// + pId);
// what is the right way to get the process ID set by 'Create' method?
}
Would be great if you could provide some pointers or relevant code. Ask me more if needed. Thanks in advance.
Replacing
Integer processId = null;
with
Variant processId = new Variant(0, true);
should solve the problem. You should then have process ID of the notepad.exe process in the processId variant, and it can be fetched by
processId.getIntRef()

Categories