Using Rhino and JSR-223 to read a JSON file - javascript

I'm trying to read a JSON file with some JavaScript that I'm eval-ing with Rhino through the Java JSR-223 API. What I'm trying to do works with the Rhino shell, but not with the embedded Javascript in my Java code.
Here's what works:
$ java -jar js.jar
js> readFile('foo.json');
{y:"abc"}
Here is what does not work:
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("js");
engine.eval("readFile('foo.json')");
I get this error:
Exception in thread "main" javax.script.ScriptException:
sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: "readFile" is not defined. (<Unknown source>#4) in <Unknown source> at line number 4
at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:153)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:232)
How can i get the readFile to be available in my engine?

If you are just trying to parse JSON, I would suggest using a JSON parsing library like Jackson or Jettison, it's a much easier approach. The readFile call returns a string, and it is not actually converting the contents into a JavaScript object. A JSON.parse or JavaScript eval call on the string would be needed in order to accomplish that.
If you really need to use the JavaScript engine to parse JSON and you were using Java 7 you could do something like this (but I wouldn't advise it)...
public static void main(final String args[]) throws Exception {
final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName("js");
Object val = null;
Scanner s = null;
try {
s = new Scanner(new File("foo.json"));
s.useDelimiter("\\Z");
engine.getBindings(ScriptContext.GLOBAL_SCOPE).put("json", s.next());
} finally {
if (s != null) {
s.close();
}
}
// The default JavaScript engine in Java 6 does not have JSON.parse
// but eval('(' + json + ')') would work
val = engine.eval("JSON.parse(json)");
// The default value is probably a JavaScript internal object and not very useful
System.out.println(val.getClass() + " = " + val);
// Java 7 uses Rhino 1.7R3 the objects will implement Map or List where appropriate
// So in Java 7 we can turn this into something a little more useable
// This is where Java 6 breaks down, in Java 6 you would have to use the
// sun.org.mozilla.javascript.internal classes to get any useful data
System.out.println(convert(val));
}
#SuppressWarnings("unchecked")
public static Object convert(final Object val) {
if (val instanceof Map) {
final Map<String, Object> result = new HashMap<String, Object>();
for (final Map.Entry<String, Object> entry: ((Map<String, Object>) val).entrySet()) {
result.put(entry.getKey(), convert(entry.getValue()));
}
return result;
} else if (val instanceof List) {
final List<Object> result = new ArrayList<Object>();
for (final Object item: ((List<Object>) val)) {
result.add(convert(item));
}
return result;
}
if (val != null) {
System.out.println(val.getClass() + " = " + val);
}
return val;
}
The JavaScript engine provided in Java has excluded some of the features provided in Rhino. The readFile function is actually provided by the Rhino Shell, not the engine implementation. Oracle also provides functions accessible by the jrunscript shell which are not in the engine.
Here's an example that mimics the Rhino shell readFile function and adds it to the JavaScript scope based upon the answer to this question:
How can I add methods from a Java class as global functions in Javascript using Rhino?
public static void main(final String args[]) throws Exception {
final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName("js");
engine.getBindings(ScriptContext.GLOBAL_SCOPE).put("utils", new Utils());
engine.eval("for(var fn in utils) {\r\n" +
" if(typeof utils[fn] === 'function') {\r\n" +
" this[fn] = (function() {\r\n" +
" var method = utils[fn];\r\n" +
" return function() {\r\n" +
" return method.apply(utils,arguments);\r\n" +
" };\r\n" +
" })();\r\n" +
" }\r\n" +
"}");
engine.eval("println(readFile('foo.json'))");
}
static class Utils {
public String readFile(final String fileName) throws FileNotFoundException {
return readFile(fileName, null);
}
public String readFile(final String fileName, final String encoding) throws FileNotFoundException {
Scanner s = null;
try {
s = new Scanner(new File(fileName), (encoding == null)? Charset.defaultCharset().name(): encoding);
s.useDelimiter("\\Z");
return s.next();
} finally {
if (s != null) {
s.close();
}
}
}
}

You can always just leverage the relevant Java classes to slurp in the JSON file, then decorate it so it's suitable for an eval().
It can be done neatly in one line. For example given the following:
cfg.json:
{
myopts: {
username: "tee",
password: "password"
}
}
And the following Javascript:
cfg = eval('(' + new java.util.Scanner( new java.io.File('cfg.json') ).useDelimiter("\\A").next() + ')');
You can now access your JSON in Javascript via:
log.info("Username: " + cfg.myopts.username ); // "Username: tee"

Related

Android Capacitor JS Plugin does not reply

I am working on a java plugin that is supposed to recieve some info from a js vue3 program and then do a URL post operation, and then return some of the info found back to the js code. I am using capacitor and android. This is my error message:
2022-08-22 13:46:23.773 27544-27544/org.theguy.GptEtc E/Capacitor/Console: File: http://localhost/js/app.6577adf2.js - Line 1 - Msg: Uncaught (in promise) SyntaxError: Unexpected token o in JSON at position 1
I think this means that something other than valid JSON is being delivered to the js code. I know that the app is delivering info to the java android class. This is some of my java code.
#CapacitorPlugin(name = "URLPOST")
public class PluginURLPost extends Plugin {
#PluginMethod()
public void post(PluginCall call) {
String post_url = call.getString("post_url", "");
String bearer = call.getString("bearer", "pipeline_");
JSObject ret = new JSObject();
try {
String value = this.doPost(post_url, bearer);
System.out.println("value " + value);
Gson gson = new Gson();
JsonReader reader = new JsonReader(new StringReader(value));
ResultPreview preview = gson.fromJson(reader, ResultPreview.class);
String val = preview.getResult_preview()[0][0];
val = "result string here."; // <-- add this for easy testing
ret.put("response_text", val.replace("\n", "\\n"));
System.out.println("response here: " + val);
}
catch (Exception e) {
e.printStackTrace();
}
//call.setKeepAlive(true);
call.resolve(ret);
}
OkHttpClient client = new OkHttpClient();
public static final MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
String doPost(String post_url, String bearer ) throws IOException {
// ... do some post request here ...
return response_body;
}
}
class ResultPreview {
#SerializedName("result_preview")
String [][] result_preview ;
public void setResult_preview(String[][] result) {
this.result_preview = result;
}
public String[][] getResult_preview() {
return this.result_preview;
}
}
This is some of my js code.
import { registerPlugin } from "#capacitor/core";
const URLPOST = registerPlugin("URLPOST");
const request = {
"line": line,
"pipeline_model": details[engine]["app_model"].trim(),
"bearer": details[engine]["api_key"].trim(),
"post_url": details[engine]["url"].trim(),
"length": 25,
"top_k": 50
};
console.log("request", request);
var {response_text} = await URLPOST.post(request);
console.log("response_text 1",response_text);
I don't know what to do.
I tried this, and things work better. I don't know if this is the ultimate solution.
#PluginMethod()
public void post(PluginCall call) {
bridge.saveCall(call); // <-- add this
call.release(bridge); // <-- add this
String pipeline_model = call.getString("pipeline_model", "pipeline_");
String post_url = call.getString("post_url", "");
JSObject ret = new JSObject();
try {
String value = this.doPost(post_url);
Gson gson = new Gson();
JsonReader reader = new JsonReader(new StringReader(value));
ResultPreview preview = gson.fromJson(reader, ResultPreview.class);
String val = preview.getResult_preview()[0][0];
ret.put("response_text", val.replace("\n", "\\n"));
System.out.println("response here: " + val);
}
catch (Exception e) {
e.printStackTrace();
}
call.resolve(ret);
}
This is not found on the capacitor site, but instead I found it digging around the internet.

Protobuf : pass protobuf message from Javascript to C++ WebAssembly module

I would like to pass a protobuf message from Javascript to a C++ WebAssembly module.
I do receive, and can successfully parse the simpler protobuf messages on the C++ side, however, protobuf is failing to parse the less-simple protobuf messages.
Here is the code that I am using :
goog.module('protobufMessageGenerator');
goog.require('proto.my_proto.MyMessage');
function generateMyMessage() {
var msg = new proto.my_proto.MyMessage()
var internal = new proto.my_proto.MyMessageInternal()
internal.setAccentColor("#CC1D24")
internal.setLogo("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")
msg.setInternal(internal)
return msg
}
Using the google-closure-compiler, I compile this protobuf message generator to pure Javascript.
I use this code to pass the message to the C++ WebAssembly module :
function sendMessage() {
Module.self().setMyMessage(module$contents$protobufMessageGenerator_generateMyMessage().serializeBinary())
}
sendMessage()
I receive the message on the C++ side using this code :
void JavascriptPublicInterface::setMyMessage(const QString &myMessage)
{
if (_myMessage != myMessage)
{
_myMessage = myMessage;
emit myMessageChanged();
}
}
void JavascriptPublicInterface::setMyMessageEMS(const std::string &myMessage)
{
setMyMessage(QString::fromStdString(myMessage));
}
//...
void startListeningToMyMessage(std::function<void(euf_proto::MyMessage myMessage)> listener)
{
const auto changedListener = [listener]() {
const auto newMyMessageString = JavascriptPublicInterface::self()->myMessage();
my_proto::MyMessage myMessagePb;
if (myMessagePb.ParseFromString(newMyMessageString.toStdString()))
{
qDebug() << "C++ : Successfully parsed new MyMessage: " << newMyMessageString;
}
else
{
qDebug() << "C++ : Failed to parse new MyMessage: " << newMyMessageString;
}
qDebug() << "MyMessage received: " << QString::fromStdString(myMessagePb.DebugString());
listener(myMessagePb);
};
if (!QObject::connect(JavascriptPublicInterface::self(), &JavascriptPublicInterface::myMessageChanged, changedListener))
{
throw std::runtime_error("Failed to connect to JavascriptPublicInterface myMessageChanged");
}
}
In the Javascript console I see : "C++ : Failed to parse new MyMessage: ..."
I guess that it can be related to the fact that Javascript is using UTF-16 and C++ is using UTF-8 encoding (because the messages that are UTF-8 only can be successfully parsed), so I tried to fix the sending and receiving like this:
//For more info see : https://emscripten.org/docs/api_reference/emscripten.h.html?highlight=stringtoutf8
function convertUtf16ToUtf8(input) {
var uint8Arr = input
var jsString = String.fromCharCode.apply(null, uint8Arr)
var lengthBytes = lengthBytesUTF8(jsString)+1
var stringOnWasmHeap = _malloc(lengthBytes)
stringToUTF8(jsString, stringOnWasmHeap, lengthBytes)
return stringOnWasmHeap
}
function sendMessage() {
var myMessage = convertUtf16ToUtf8(module$contents$protobufMessageGenerator_generateMyMessage().serializeBinary())
Module.self().setMyMessage(myMessage)
_free(myMessage)
}
sendMessage()
And I modified the parsing on the C++ side like this :
void JavascriptPublicInterface::setMyMessageEMS(const int pointer)
{
const char* msg = (char*)pointer;
setMyMessage(QString::fromStdString(msg));
}
But I still get this error : "C++ : Failed to parse new MyMessage: ..."
How could I fix this?
(I am using protobuf 3.19.1 (same version on both the Javascript and the C++ side).)
UPDATE :
In case if I modify my code, so it is passing a simple string as logo, then I can successfully parse the protobuf message on the C++ side :
internal.setLogo("logo")
So I guess that the issue is with this field.
The original string is a base64 encoded image.
What should I do with this string to fix the parsing?
I found the solution.
This stackoverflow post described a really similar issue, and it helped me to fix my parsing as well :
Protobuf: Serialize/DeSerialize C++ to Js
Here is my updated code, which works well :
I had to update the Javascript side :
function sendMessage() {
Module.self().setMyMessage(module$contents$protobufMessageGenerator_generateMyMessage().serializeBinary().toString())
}
sendMessage()
and the C++ side :
namespace
{
QByteArray decryptProtobufMessage(const std::string &str)
{
QStringList strList = QString::fromStdString(str).split(',');
QByteArray bytedata;
foreach (const QString &str, strList)
{
bytedata += (str.toUInt());
}
return bytedata;
}
} // namespace
void JavascriptPublicInterface::setMyMessage(const QByteArray &myMessage)
{
if (_myMessage != myMessage)
{
_myMessage = myMessage;
emit myMessageChanged();
}
}
void JavascriptPublicInterface::setMyMessageEMS(const std::string &myMessage)
{
setMyMessage(decryptProtobufMessage(myMessage));
}
//...
void startListeningToMyMessage(std::function<void(euf_proto::MyMessage myMessage)> listener)
{
const auto changedListener = [listener]() {
const auto newMyMessageByteArray = JavascriptPublicInterface::self()->myMessage();
my_proto::MyMessage myMessagePb;
if (myMessagePb.ParseFromArray(newMyMessageByteArray.data(), newMyMessageByteArray.size()))
{
qDebug() << "C++ : Successfully parsed new MyMessage: " << newMyMessageByteArray;
}
else
{
qDebug() << "C++ : Failed to parse new MyMessage: " << newMyMessageByteArray;
}
qDebug() << "MyMessage received: " << QString::fromStdString(myMessagePb.DebugString());
listener(myMessagePb);
};
if (!QObject::connect(JavascriptPublicInterface::self(), &JavascriptPublicInterface::myMessageChanged, changedListener))
{
throw std::runtime_error("Failed to connect to JavascriptPublicInterface myMessageChanged");
}
}

Generate HMAC SHA Algorithm using URI and Key

I wrote a Java program which generates HMAC SHA hash code, But due to some reason I have to write the same code in NodeJs/JavaScript. I tried googling around but did not get anything. In this Java code, I am passing URI and Key as arguments, to generate the hash code, where URI contains Timestamp.
The java code is as :
public static String calcMAC(String data, byte[] key) throws Exception {
String result=null;
SecretKeySpec signKey = new SecretKeySpec(key, SecurityConstants.HMAC_SHA1_ALGORITHM);
Mac mac = Mac.getInstance(SecurityConstants.HMAC_SHA1_ALGORITHM);
mac.init(signKey);
byte[] rawHmac;
try {
rawHmac = mac.doFinal(data.getBytes("US-ASCII"));
result = Base64.encodeBase64String(rawHmac);
} catch (Exception e) {
e.printStackTrace();
}
return result.trim();
}
public static void main(String args[]) {
String timestamp = args[0];
String key = "d134hjeefcgkahvg32ajkdbaff84ff180";
String out = null;
try {
out = calcMAC("/req?app_id=47ca34" + timestamp + "=2018-05-22T12:02:15Z",
key.getBytes());
System.out.println(URLEncoder.encode(out, "UTF-8"));
} catch (Exception e) {
e.printStackTrace();
}
}
Is it possible to achieve the same goal in NodeJs/JavaScript?
Note:: I have to call this script from Postman pre-request script.
The crypto module should do this for you, you can substitute the 'data' variable with whatever you want to hash:
const crypto = require('crypto');
const data = 'The fault dear Brutus lies not in our stars';
const key = Buffer.from('d134hjeefcgkahvg32ajkdbaff84ff180', 'utf8');
const hash = crypto.createHmac('sha1', key).update(data).digest('base64');
const uriEncodedHash = encodeURIComponent(hash);
console.log('Hash: ' + uriEncodedHash);
Hashing the data in both Java and Node.js gives me the result (URI Encoded) of:
TJJ3xj93m8bfVpGoucluMQqkB0o%3D
The same Java code would be:
public static void main(String args[]) {
String data = "The fault dear Brutus lies not in our stars";
String key = "d134hjeefcgkahvg32ajkdbaff84ff180";
String out = null;
try {
out = calcMAC(data, key.getBytes());
System.out.println(URLEncoder.encode(out, "UTF-8"));
} catch (Exception e) {
e.printStackTrace();
}
}
Again, we can put anything into 'data' we want.

j2v8 Object from nodejs script not accesible

I try to run a nodeJS script with j2v8 in my Java project and it runs normally but i can't get the Array or any other JScript Objects although this functionality is offered through j2v8. Additionally the script uses a npm module called Blocktrail which generates the Array. The call for the Object is in the function testExportAnalyzer(). Here it throws that the Object does not contain "test". Please, can anyone explain how i can use the variables or the needed Array in my Java Code or what I do wrong?
public ScriptLoader(String adr) {
address = adr;
addressInformation = null;
NODE_SCRIPT = ""
+"var test = \"123456\";\n"
+"var blocktrail = require('/blocktrail-sdk');\n"
+"var addressInformation = null;\n"
+"var client = blocktrail.BlocktrailSDK({apiKey : \"xxxxxx\", apiSecret : \"xxxxxx\"});\n"
+"client.address(\""+address+"\", function(err, address) {\n"
+" if (err) {\n"
+" console.log('address ERR', err);\n"
+" return;\n"
+" }\n"
+" addressInformation = address;"
+"console.log('address:', address['address'], 'balance:', address['balance'] / blocktrail.COIN, 'sent and received in BTC:', address['sent'] / blocktrail.COIN, address['received'] / blocktrail.COIN, 'number of transactions:', address['total_transactions_out'], address['total_transactions_in']);\n"
+"});\n"
+"\n"
+"client.addressTransactions(\""+address+"\", {limit: 100}, function(err, address_txs) {\n"
+" console.log('address_transactions', address_txs['data'].length, address_txs['data'][0]);\n"
+"});";
}
public void executeAnalyzerScript() throws IOException {
final NodeJS nodeJS = NodeJS.createNodeJS();
JavaCallback callback = new JavaCallback() {
public Object invoke(V8Object receiver, V8Array parameters) {
return "Hello, JavaWorld!";
}
};
nodeJS.getRuntime().registerJavaMethod(callback, "someJavaMethod");
File nodeScript = createTemporaryScriptFile(NODE_SCRIPT, "addressScript");
nodeJS.exec(nodeScript);
while(nodeJS.isRunning()) {
nodeJS.handleMessage();
}
nodeJS.release();
}
public void testExportAnalyzer() throws IOException {
NodeJS nodeJS = null;
File testScript = createTemporaryScriptFile(NODE_SCRIPT, "Test");
nodeJS = NodeJS.createNodeJS();
V8Object exports = nodeJS.require(testScript);
while(nodeJS.isRunning()) {
nodeJS.handleMessage();
}
System.out.println(exports.contains("test"));
exports.release();
}
private static File createTemporaryScriptFile(final String script, final String name) throws IOException {
File tempFile = File.createTempFile(name, ".js.tmp");
PrintWriter writer = new PrintWriter(tempFile, "UTF-8");
try {
writer.print(script);
} finally {
writer.close();
}
return tempFile;
}
public void setAddress(String input) {
address = input;
}
I had some success by writing variables like this in the Javascript code:
global.myvar = "myval";

Using Fineuploader with ASP.NET webforms. access to strict mode caller function is censored

I am currently using fineuploader with ASP.NET webforms and am encountering a problem with strict mode in FireFox. ASP.NET webforms has a javascript file (microsoftajaxwebforms.js) that contains the following code (This is used to postback to the server and call the passed event, ex. Save below.):
_doPostBack: function(a, k) {
var f = window.event;
if (!f) {
var d = arguments.callee ? arguments.callee.caller : null;
if (d) {
var j = 30;
while (d.arguments.callee.caller && --j) d = d.arguments.callee.caller;
f = j && d.arguments.length ? d.arguments[0] : null
}
}
...
That function is used liberally in the codebase I am working with. I cannot change this code for fear of unintended side-effects in the rest of the product. The problem is with the arguments.callee.caller. That is what is throwing the error access to strict mode caller function is censored. I believe the solution is to remove the use strict from the fineuploader.js, but I am worried about how that might effect fineuploader in other browsers. I am not familiar with strict mode in javascript, so maybe someone can shed some light on the possible side-effects of removing strict mode from the fineuploader.js. For reference, here is the fineuploader function that eventually calls the above code and causes the error.
var fineUploader = $('#jquery-wrapped-fine-uploader').fineUploader({
...
multiple: false,
text: {
uploadButton: 'Click or drag a file to upload.'
},
autoUpload: false,
debug: false,
template: 'fineuploader-template',
...
}
}).bind('complete', function (event, id, name, response) {
if (response['success']) {
cp_hide();
fineUploader.fineUploader('reset');
__doPostBack("Save", "");
}
})...
I can modify anything short of the code referenced from microsoftajaxwebforms.js if needed. I appreciate any help.
The workaround according to the jQuery ticket (http://bugs.jquery.com/ticket/13335) is to manually call the event on the client side rather than calling __doPostBack directly.
$('#Save').trigger('click');
However, if you are trying to trigger a postback from within the client-side event, the trigger option won't work. Instead, you can use ugly, yet trusty setTimeout to get out of strict mode.
$('#Save').on('click', function(e) {
var result = doSomeStuff();
if(result.success) {
window.setTimeout(function() { __doPostBack('Save', '') }, 5);
}
// ...
});
jQuery eventually removed use strict 2 years ago, so upgrading the jQuery (if possible) should also solve the issue.
As aditional information, there's actually an ASP.NET WebForms VB and ASP.NET MVC C# examples if you need to do stuffs like write to database when uploading the files:
VB example:
Imports System.Data.SqlClient
Imports System.Net
Imports System.IO
Namespace Uploader
Public Class UploadController
Inherits System.Web.Mvc.Controller
<HttpPost()> _
Function Upload(ByVal uploadFile As String) As String
On Error GoTo upload_error
Dim strm As Stream = Request.InputStream
Dim br As BinaryReader = New BinaryReader(strm)
Dim fileContents() As Byte = {}
Const ChunkSize As Integer = 1024 * 1024
' We need to hand IE a little bit differently...
If Request.Browser.Browser = "IE" Then
Dim myfiles As System.Web.HttpFileCollection = System.Web.HttpContext.Current.Request.Files
Dim postedFile As System.Web.HttpPostedFile = myfiles(0)
If Not postedFile.FileName.Equals("") Then
Dim fn As String = System.IO.Path.GetFileName(postedFile.FileName)
br = New BinaryReader(postedFile.InputStream)
uploadFile = fn
End If
End If
' Nor have the binary reader on the IE file input Stream. Back to normal...
Do While br.BaseStream.Position < br.BaseStream.Length - 1
Dim b(ChunkSize - 1) As Byte
Dim ReadLen As Integer = br.Read(b, 0, ChunkSize)
Dim dummy() As Byte = fileContents.Concat(b).ToArray()
fileContents = dummy
dummy = Nothing
Loop
' You now have all the bytes from the uploaded file in 'FileContents'
' You could write it to a database:
'Dim con As SqlConnection
'Dim connectionString As String = ""
'Dim cmd As SqlCommand
'connectionString = "Data Source=DEV\SQLEXPRESS;Initial Catalog=myDatabase;Trusted_Connection=True;"
'con = New SqlConnection(connectionString)
'cmd = New SqlCommand("INSERT INTO blobs VALUES(#filename,#filecontents)", con)
'cmd.Parameters.Add("#filename", SqlDbType.VarChar).Value = uploadFile
'cmd.Parameters.Add("#filecontents", SqlDbType.VarBinary).Value = fileContents
'con.Open()
'cmd.ExecuteNonQuery()
'con.Close()
' Or write it to the filesystem:
Dim writeStream As FileStream = New FileStream("C:\TEMP\" & uploadFile, FileMode.Create)
Dim bw As New BinaryWriter(writeStream)
bw.Write(fileContents)
bw.Close()
' it all worked ok so send back SUCCESS is true!
Return "{""success"":true}"
Exit Function
upload_error:
Return "{""error"":""An Error Occured""}"
End Function
End Class
End Namespace

Categories

Resources