I have javascript file (jalali.js) which it have a lot of functions.
I want to call one of this functions in my java web application project (I mean somefile.Class file)
I had some research and i found these two methods:
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
engine.eval("print('Hello, World')");
But I can not understand how to call my js file (jalali.js) and how should i call my function
I will put function detail code here (from jalali.js)
JalaliDate.gregorianToJalali = function(g_y, g_m, g_d)
{
g_y = parseInt(g_y);
g_m = parseInt(g_m);
g_d = parseInt(g_d);
var gy = g_y-1600;
var gm = g_m-1;
var gd = g_d-1;
...
...
return [jy, jm, jd];
}
I want to use that function in my java application (MyClass.class)
public class TaskListModel extends BaseModel{
private Date gDate;
private String jalaliDate;
public void setGDate(Date gDate) {
this.gDate= gDate;
this.jalaliDate = Here i need call the js function ;
}
Well if this is the Rhino engine from 1.6 Java, then you can evaluate the code in jalali.js line by line - keeping the instance of engine alive through the runtime of the file. Also you can then execute the function like this: engine.eval("myfunction(arg1, arg2);");
I am not sure what you are trying to achieve
Step1. Read a line of the jalali.js file
Step2. engine.eval() the line
Step3. check if EOF - if yes, go to Step4 else go to Step1
Step4. engine.eval("your_function(arg1, arg2);");
a simple solution would be you read the whole file and append to it the function call you want to make and pass the modified contents to the eval method. so the final content passed to eval would take the form of
//
script in your .js file
//
return functionInYourJs(arg1, arg2);
Probably once the file is read you can cache it to avoid repeated disk reads.
Related
This question already has answers here:
How to call Java code from C#?
(4 answers)
Closed 1 year ago.
I have a requirement to compile and run java programs from C# dynamically by passing parameters.
Ex: below is java code i have to execute this code from c# by passing parameters num1, num2. How to do in c#?
import java.util.Scanner;
public class AddTwoNumbers2 {
public int CalAdd(int num1, int num2) {
return num1 + num2;
}
}
I am looking for calling Java code file in c# like below, python code called in c# example code
var engine = Python.CreateEngine();
var scope = engine.CreateScope();
//try
//{
var compilerOptions = (PythonCompilerOptions)engine.GetCompilerOptions();
ErrorSinkProxyListener(errorSink);
var scriptSource = engine.CreateScriptSourceFromFile(#"C:\Nidec\PythonScript\download_nrlist.py", Encoding.UTF8, Microsoft.Scripting.SourceCodeKind.File);
var compiledCode = scriptSource.Compile();
compiledCode.Execute(scope);
engine.ExecuteFile(#"C:\Nidec\PythonScript\download_nrlist.py", scope);
//get function and dynamically invoke
var calcAdd = scope.GetVariable("CalcAdd");
result = calcAdd(34, 8); // returns 42 (Int32)
You can put the java run commands inside a .sh or .bat file and then use System.Diagnostics.ProcessStartInfo in your C# method to execute that shell script/batch file.
Code snippet:
class MyProcess {
// Opens urls and .html documents using Internet Explorer.
void OpenWithArguments()
{
// url's are not considered documents. They can only be opened
// by passing them as arguments.
Process.Start("IExplore.exe", "www.northwindtraders.com");
// Start a Web page using a browser associated with .html and .asp files.
Process.Start("IExplore.exe", "C:\\myPath\\myFile.htm");
Process.Start("IExplore.exe", "C:\\myPath\\myFile.asp");
}
static void Main()
{
MyProcess myProcess = new MyProcess();
myProcess.OpenWithArguments();
}
}
Refer this
tl;dr:
How do/can I store the function-handles of multiple js-functions in java for using them later? Currently I have two ideas:
Create multipe ScriptEngine instances, each containing one loaded function. Store them in a map by column, multiple entries per column in a list. Looks like a big overhead depending on how 'heavy' a ScriptEngine instance is...
Some Javascript solution to append methods of the same target field to an array. Dont know yet how to access that from the java-side, but also dont like it. Would like to keep the script files as stupid as possible.
var test1 = test1 || [];
test1.push(function(input) { return ""; });
???
Ideas or suggestions?
Tell me more:
I have a project where I have a directory containing script files (javascript, expecting more than hundred files, will grow in future). Those script files are named like: test1;toupper.js, test1;trim.js and test2;capitalize.js. The name before the semicolon is the column/field that the script will be process and the part after the semicolon is a human readable description what the file does (simplified example). So in this example there are two scripts that will be assigned to the "test1" column and one script to the "test2" column. The js-function template basically looks like:
function process(input) { return ""; };
My idea is, to load (and evaluate/compile) all script files at server-startup and then use the loaded functions by column when they are needed. So far, so good.
I can load/evaluate a single function with the following code. Example uses GraalVM, but should be reproducable with other languages too.
final ScriptEngine engine = new ScriptEngineManager().getEngineByName("graal.js");
final Invocable invocable = (Invocable) engine;
engine.eval("function process(arg) { return arg.toUpperCase(); };");
var rr0 = invocable.invokeFunction("process", "abc123xyz"); // rr0 = ABC123XYZ
But when I load/evaluate the next function with the same name, the previous one will be overwritten - logically, since its the same function name.
engine.eval("function process(arg) { return arg + 'test'; };");
var rr1 = invocable.invokeFunction("process", "abc123xyz"); // rr1 = abc123xyztest
This is how I would do it.
The recommended way to use Graal.js is via the polyglot API: https://www.graalvm.org/reference-manual/embed-languages/
Not the same probably would work with the ScriptEngine API, but here's the example using the polyglot API.
Wrap the function definition in ()
return the functions to Java
Not pictured, but you probably build a map from the column name to a list of functions to invoke on it.
Call the functions on the data.
import org.graalvm.polyglot.*;
import org.graalvm.polyglot.proxy.*;
public class HelloPolyglot {
public static void main(String[] args) {
System.out.println("Hello Java!");
try (Context context = Context.create()) {
Value toUpperCase = context.eval("js", "(function process(arg) { return arg.toUpperCase(); })");
Value concatTest = context.eval("js", "(function process(arg) { return arg + 'test'; })");
String text = "HelloWorld";
text = toUpperCase.execute(text).asString();
text = concatTest.execute(text).asString();
System.out.println(text);
}
}
}
Now, Value.execute() returns a Value, which I for simplicity coerce to a Java String with asString(), but you don't have to do that and you can operate on Value (here's the API for Value: https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html).
I have two js files,
one is js library
second one is a simple script usually somewhat around 50 lines, that needs to access functions from the library.
In my project im trying to precompile all javascripts during my application startup, and then at runtime only invoke CompiledScripts with desired parameters.
I ended up with the following code
static String LIBRARY = "function hello(arg) {return 'Hello ' + arg;};";
static String SCRIPT = "hello(arg)";
public static void main(String... args) throws Exception {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("Nashorn");
Compilable compilable = ((Compilable) engine);
CompiledScript compiledLib = compilable.compile(LIBRARY);
compiledLib.eval();
CompiledScript actualScript = compilable.compile(SCRIPT);
Bindings helloParams = new SimpleBindings();
helloParams.put("arg","world");
ScriptObjectMirror result = (ScriptObjectMirror) actualScript.eval(helloParams);
System.out.println(result);
}
But this code throws an error
> compiledScript.eval(helloParams);
<eval>:1 ReferenceError: "hello" is not defined
How can i access context of "compiledLib" (ie methods and variables) from within the "actualScript"?
Compiling doesn't register the hello() function, it just parses the JavaScript code.
You need to execute the code for the function to be registered.
Remember, in JavaScript, there is very little difference between these two statements, except that function declarations are hoisted and can therefore be used before the declaration statement:
function hello(arg) {return 'Hello ' + arg;};
var hello = function(arg) {return 'Hello ' + arg;};
There is therefore little reason to separately compile the LIBRARY code, you just run it and save off all the created global variables, which are the library methods. E.g. after executing your LIBRARY code, you'll have a global variable named hello.
ScriptEngine engine = new ScriptEngineManager().getEngineByName("Nashorn");
Compilable compilable = ((Compilable) engine);
// Process LIBRARY code
Bindings bindings = new SimpleBindings();
engine.eval(LIBRARY, bindings);
// Compile SCRIPT code
CompiledScript actualScript = compilable.compile(SCRIPT);
// Run SCRIPT code
bindings.put("foo", "world");
Object result = actualScript.eval(bindings);
System.out.println(result);
Output
Hello world
To begin, I'm aware of this question, but I don't think it quite fits what I'm doing. Either way, the answer is a bit confusing my opinion. I'd like to find an answer for my problem that's more specific to what I'm doing.
The goal here is for the lua file chatterToolsTest to successfully print "Test success" to the console. Unfortunately, my current approach isn't quite working. Can someone please help? I'm not the best at Lua, so maybe my Lua code is just wrong in this case. Please check out the snippets below.
Another constraint: I can't enable to use of modules from the java-side. Any referencing done between the two Lua files has to be obtained through Lua only. This is because I'm developing a modding system for a Java project and need the Lua to be able to work with minimal change on the Java-side.
Please keep in mind that I'm not storing my Lua files inside of the JAR file or any packages, they are contained in a folder in the root working directory of the Java program, like a folder of resources.
chatterToolsTest.lua:
function main()
print("Test start.");
local test = require("chatterTools");
chatterTools:test();
end
chatterTools.lua, the class called by chatterToolsTest.lua:
function test()
print("Test success");
end
Both of these files are in a folder called world/NOKORIWARE/lua/:
And lastly, here's the Java test class using LuaJ that calls them:
public class LuaTest {
public static void main(String args[]) {
new LuaTest().run("NOKORIWARE/lua/chatterToolsTest.lua", "main");
}
private Globals buildGlobals() {
Globals globals = new Globals();
globals.load(new JseBaseLib());
globals.load(new PackageLib());
globals.load(new Bit32Lib());
globals.load(new TableLib());
globals.load(new StringLib());
globals.load(new JseMathLib());
globals.load(new WhitelistedLuajavaLib());
LoadState.install(globals);
LuaC.install(globals);
return globals;
}
/**
* Runs the given lua file. It must be relative to the lua path.
*/
private void run(String luaPath, String functionName, Object... arguments) {
LuaValue[] coercedValues = null;
if (arguments != null) {
//Coerce arguments into LuaValues
coercedValues = new LuaValue[arguments.length];
for (int i = 0; i < arguments.length; i++) {
coercedValues[i] = CoerceJavaToLua.coerce(arguments[i]);
}
}
//Configure lua file
Globals globals = buildGlobals();
globals.get("dofile").call(LuaValue.valueOf("./world/" + luaPath));
//Call the passed-in function of the lua file.
try {
LuaValue call = globals.get(functionName);
if (arguments != null) {
call.invoke(coercedValues);
}else {
call.invoke();
}
} catch (Exception e) {
e.printStackTrace();
TinyFileDialog.showMessageDialog("Caught " + e.getClass().getName(), e.getMessage(), TinyFileDialog.Icon.INFORMATION);
}
}
}
This is the error that's printed when I run the Java program:
org.luaj.vm2.LuaError: #./world/NOKORIWARE/lua/chatterToolsTest.lua:4 module 'chatterTools' not found: chatterTools
no field package.preload['chatterTools']
chatterTools.lua
no class 'chatterTools'
at org.luaj.vm2.LuaValue.error(Unknown Source)
at org.luaj.vm2.lib.PackageLib$require.call(Unknown Source)
at org.luaj.vm2.LuaClosure.execute(Unknown Source)
at org.luaj.vm2.LuaClosure.onInvoke(Unknown Source)
at org.luaj.vm2.LuaClosure.invoke(Unknown Source)
at org.luaj.vm2.LuaValue.invoke(Unknown Source)
at nokori.robotfarm.test.LuaTest.run(LuaTest.java:64)
at nokori.robotfarm.test.LuaTest.main(LuaTest.java:21)
Any help or links to relevant resources is appreciated.
The default LuaJ working directory is the same as Java's. Once I figured that out, I was able to correctly use require().
chatterTools.lua was changed to this:
local chatterTools = {}
function chatterTools.test()
print("Test success");
end
return chatterTools;
And finally chatterToolsTest.lua had to be changed like this:
function main()
print(package.path);
local chatterTools = require("world.NOKORIWARE.lua.chatterTools");
chatterTools:test();
end
Lua handles packages like above, so instead of world/NOKORIWARE/lua/chatterTools.lua it turns into what you see in the require() call.
After these changes, I ran the program and got the following:
?.lua
Test success
All of this considered, this solution is a lot more straight-forward than the answer in the question I linked at the start of this question. Hopefully this will help some of you out there.
To read more on how I figured this out, check these resources out:
how to call function between 2 .lua
https://forums.coronalabs.com/topic/38127-how-to-call-a-function-from-another-lua-file/
Is there any good documentation how to invoke a lambda function from a lambda function written in java?
Is there a difference between invoking a lambda function from a lambda function or invoke from a normal java application?
The only thing that I found is the normal AWS Java SDK doc.
http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/index.html
Would be happy if someone could help me.
Yes, you can call lambdas normally from lambdas, just as you would if your code was executing on a host somewhere.
You'll have an additional step of ensuring that the lambda executing the call to another lambda has permissions to execute other lambda functions (the permission is called "lambda:InvokeFunction").
The rest of the steps are the same as regular java using the AWS SDK, you instantiate an AWSLambdaClient object, set your credentials and settings (region, etc.) and then create an InvokeRequest object which is the sub-lambda to be called with the appropriate payload.
Here's some sample java code which does exactly this, but it's also part of the standard sdk docs.
And also keep in mind that you'll still be subject to the original timeout for the first lambda, otherwise execution will be stopped.
Here's the relevant code snippets that you should be able to work from, I've made a change to how the second lamdba is called in terms of credentials - your can pass the credentials used to invoke the first lambda implicitly into the second one, which is probably a bit easier and more maintainable - you just need to ensure that the first lambda call gets the credentials and the rest will inherit them.
Region region;
AWSLambdaClient lambdaClient;
lambdaClient = new AWSLambdaClient(new DefaultAWSCredentialsProviderChain());
region = Region.getRegion(Regions.fromName(regionName));
lambdaClient.setRegion(region);
InvokeRequest invokeRequest = new InvokeRequest();
invokeRequest.setFunctionName(FunctionName);
invokeRequest.setPayload(ipInput);
returnDetails = byteBufferToString(
lambdaClient.invoke(invokeRequest).getPayload(),
Charset.forName("UTF-8"),logger);
edit: I should also point out that depending on your architecture, there's probably much cleaner options like using SQS, or depending on how simple your nested lambdas are, inlining them directly inside each other to avoid the extra call.
A lot of the used API functions are deprecated and the AWS docu is ... I share a new implemented example. The Lambda function "updateS3Chart" calls another Lambda function "AsyncUpdate" asynchronous:
public class LambdaInvoker {
static final Logger logger = LogManager.getLogger(LambdaInvoker.class);
static final String LambdaFunctionName = "AsyncUpdate";
private class AsyncLambdaHandler implements AsyncHandler<InvokeRequest, InvokeResult>
{
public void onSuccess(InvokeRequest req, InvokeResult res) {
logger.debug("\nLambda function returned:");
ByteBuffer response_payload = res.getPayload();
logger.debug(new String(response_payload.array()));
}
public void onError(Exception e) {
logger.debug(e.getMessage());
}
}
public void updateS3Chart(UpdateS3ChartRequest updateS3ChartRequest) {
Gson gson = new Gson();
try {
//issue: aws region is not set to debug-time. solution for eclipse:
//environment variable is set by lambda container or eclipse ide environment variables
//use instead for eclipse debugging: project -> Run as -> Run Configurations -> Environment -> Add variable: "AWS_REGION": "eu-central-1"
AWSLambdaAsync lambda = AWSLambdaAsyncClientBuilder.defaultClient(); //Default async client using the DefaultAWSCredentialsProviderChain and DefaultAwsRegionProviderChain chain
InvokeRequest req = new InvokeRequest()
.withFunctionName(LambdaFunctionName)
.withPayload(gson.toJson(updateS3ChartRequest));
Future<InvokeResult> future_res = lambda.invokeAsync(req, new AsyncLambdaHandler());
logger.debug("Waiting for async callback");
while (!future_res.isDone() && !future_res.isCancelled()) {
// perform some other tasks...
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
logger.debug("Thread.sleep() was interrupted!");
}
System.out.print(".");
}
} catch (Exception e) {
logger.fatal("Execute async lambda function: " + LambdaFunctionName + " failed: " + e.getMessage());
}
}
}
You have to set your AWS region as system property in your IDE for debugging (see comment in source code for Eclipse). UpdateS3ChartRequest is simple POJO with property set/get.