j2v8 Object from nodejs script not accesible - javascript

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";

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.

How to send data from Node to another server

I am trying to figure out a way to use Node as a client that would send out data to a server listening on an Android app. The android app will initially send a post request to the Node server with its public IP address and the port it will be listening on (socket). Once there is anything new, the Node server would then send a packet of JSON data onto that particular app via the registered socket.
Is this possible in Node, and if not how can I implement it in Javascript, or what is the best way to implement this?
Here is the Android app server
public class AndroidAppLocalServer {
Activity activity;
ServerSocket serverSocket;
String message = "";
static final int socketServerPORT = 8080;
public AndroidAppLocalServer(Activity activity) {
this.activity = activity;
Thread socketServerThread = new Thread(new SocketServerThread());
socketServerThread.start();
}
public int getPort() {
return socketServerPORT;
}
public void onDestroy() {
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class SocketServerThread extends Thread {
int count = 0;
#Override
public void run() {
try {
// create ServerSocket using specified port
serverSocket = new ServerSocket(socketServerPORT);
while (true) {
// block the call until connection is created and return
// Socket object
Socket socket = serverSocket.accept();
count++;
message += "#" + count + " from "
+ socket.getInetAddress() + ":"
+ socket.getPort() + "\n";
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Log.v("MyApp", message);
}
});
SocketServerReplyThread socketServerReplyThread = new SocketServerReplyThread(socket, count);
socketServerReplyThread.run();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class SocketServerReplyThread extends Thread {
private Socket hostThreadSocket;
int cnt;
SocketServerReplyThread(Socket socket, int c) {
hostThreadSocket = socket;
cnt = c;
}
#Override
public void run() {
OutputStream outputStream;
String msgReply = "Hello from AndroidAppLocalServer, you are #" + cnt;
try {
outputStream = hostThreadSocket.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
printStream.print(msgReply);
printStream.close();
message += "replayed: " + msgReply + "\n";
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Log.v("MyApp", message);
}
});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
message += "Something wrong! " + e.toString() + "\n";
}
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Log.v("MyApp", message);
}
});
}
}
public String getIpAddress() {
String ip = "";
try {
Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface.getNetworkInterfaces();
while (enumNetworkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = enumNetworkInterfaces.nextElement();
Enumeration<InetAddress> enumInetAddress = networkInterface.getInetAddresses();
while (enumInetAddress.hasMoreElements()) {
InetAddress inetAddress = enumInetAddress.nextElement();
if (inetAddress.isSiteLocalAddress()) {
ip += "AndroidAppLocalServer running at : " + inetAddress.getHostAddress();
}
}
}
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ip += "Something Wrong! " + e.toString() + "\n";
}
return ip;
}
}
Yes you can do this in Node.js, assuming that the App runs on a phone that is actually publicly reachable. Since you are using a plain TCP socket in your Android application, you can verify first by manually connecting the socket by using a tool such as netcat or telnet (e.g., netcat <PUBLIC-IP> 8080).
If this works you can do the same thing from within Node.js by using the net.Socket class.
const net = require('net');
const client = new net.Socket();
client.connect(8080, '<PUBLIC-IP>', () => {
// callback, when connection successfull
client.write('Data sent to the App');
});
client.on('data', (data) => {
// callback, when app replies with data
});
client.on('close', (data) => {
// callback, when socket is closed
});
However, depending on what you actually try to achieve, you might want check out how Android applications usually implement push notifications.

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.

loading an image file hosted in assets folder exposed with web server in the app

In my app, I have created web server which is hosting a web app. All the files of web app are placed in assets folder.
Now, i start the web server by running my application and then from crome brower, I try to run my web app by calling index.html file. The html, css part of the page is getting loaded properly but the images are not getting loaded in the page:
Here is my HttpRequestHandlerCode:
public class HomePageHandler implements HttpRequestHandler {
private Context context = null;
private static final Map<String, String> mimeTypes = new HashMap<String, String>() {
{
put("css", "text/css");
put("htm", "text/html");
put("html", "text/html");
put("xhtml", "text/xhtml");
put("xml", "text/xml");
put("java", "text/x-java-source, text/java");
put("md", "text/plain");
put("txt", "text/plain");
put("asc", "text/plain");
put("gif", "image/gif");
put("jpg", "image/jpeg");
put("jpeg", "image/jpeg");
put("png", "image/png");
put("svg", "image/svg+xml");
put("mp3", "audio/mpeg");
put("m3u", "audio/mpeg-url");
put("mp4", "video/mp4");
put("ogv", "video/ogg");
put("flv", "video/x-flv");
put("mov", "video/quicktime");
put("swf", "application/x-shockwave-flash");
put("js", "application/javascript");
put("pdf", "application/pdf");
put("doc", "application/msword");
put("ogg", "application/x-ogg");
put("zip", "application/octet-stream");
put("exe", "application/octet-stream");
put("class", "application/octet-stream");
put("m3u8", "application/vnd.apple.mpegurl");
put("ts", " video/mp2t");
}
};
public HomePageHandler(Context context){
this.context = context;
}
#Override
public void handle(HttpRequest request, HttpResponse response, HttpContext httpContext) throws HttpException, IOException {
//String contentType = "text/html";
//Log.i("Sushill", "..request : " + request.getRequestLine().getUri().toString());
final String requestUri = request.getRequestLine().getUri().toString();
final String contentType = contentType(requestUri);
String resp = Utility.openHTMLStringFromAssets(context, "html" + requestUri);
writer.write(resp);
writer.flush();
// }
}
});
((EntityTemplate) entity).setContentType(contentType);
response.setEntity(entity);
}
}
/**
* Get content type
*
* #param fileName
* The file
* #return Content type
*/
private String contentType(String fileName) {
String ext = "";
int idx = fileName.lastIndexOf(".");
if (idx >= 0) {
ext = fileName.substring(idx + 1);
}
if (mimeTypes.containsKey(ext)) {
//Log.i("Sushill", "...ext : " + ext);
return mimeTypes.get(ext);
}
else
return "application/octet-stream";
}
To handle image, I tried this but it did not work :
if(contentType.contains("image")) {
InputStream is = Utility.openImageFromAssets(context, "html" + requestUri);
char[] buffer = new char[1024];
try {
Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Can someone please help me in figuring out how to load the images also in my browser.
Thanks for any help
Do away with BufferedReader(new InputStreamReader' so you do away with UTF-8 too. Use only InputStream 'is'. Do away with writer. You are not showing what 'writer' is but do away with it. Use the OutputStream of the http connection. Keep the buffer and the loop where you read in the buffer and write from the buffer.

Using Rhino and JSR-223 to read a JSON file

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"

Categories

Resources