Put java class to nashorn's global scope - java

I use sandboxed Nashorn like this:
ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine(
new String[]{"--no-java", "--no-syntax-extensions", "--optimistic-types=true", "--language=es6"},
null);
But I want to use a single particular class in my javascript. How to do that?
For example, I have a class:
class MyClass
{
public void m1()
{
System.out.println("This is m1");
}
public void m2()
{
System.out.println("This is m2");
}
}
And I want to use it in the script like
let a=new MyClass();
a.m1();
a.m2();
How to do that?
Thank you

you can use Bindings to provide java objects to the ScriptEngine:
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
import javax.script.Bindings;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
public class MyClass {
public static void main(String[] args) {
ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine(
new String[]{"--no-java", "--no-syntax-extensions", "--optimistic-types=true", "--language=es6"},
null);
Bindings bindings = engine.createBindings();
bindings.put("myclass", new MyClass());
engine.setBindings(bindings, ScriptContext.GLOBAL_SCOPE);
String code = "myclass.m1();";
try {
engine.eval(code, bindings);
} catch (ScriptException e) {
e.printStackTrace();
}
}
public void m1() {
System.out.println("This is m1");
}
public void m2(String str) {
System.out.println("This is m2 " + str);
}
public void m3(Class claz) {
System.out.println(claz);
}
}
or if MyClass really needs to be instantiated in the JS code you could do (works with Java >=9):
Bindings bindings = engine.createBindings();
bindings.put("myclass", StaticClass.forClass(MyClass.class));
var code = "var a = new myclass(); a.m1();";
try {
engine.eval(code, bindings);
} catch (ScriptException e) {
e.printStackTrace();
}

Related

Runtime Exec output

I want to execute a class method that is present in another file. I am doing the following:
import java.io.IOException;
public class run_java_program {
public static void main(String[] args) {
try {
Process process = Runtime.getRuntime().exec("java -cp C:\\Users\\96171\\eclipse-workspace\\IR_Project\\src test");
} catch (IOException e) {
e.printStackTrace();
}
}
}
But its not working. However on the cmd it is:
I tried replacing C:\\Users\\96171\\eclipse-workspace\\IR_Project\\src with C:/Users/96171/eclipse-workspace/IR_Project/src but still nothing is printed out to the console.
Here is the other program:
//import py4j.GatewayServer;
public class test {
public static void addNumbers(int a, int b) {
System.out.print(a + b);
}
// public static void addNumbers(int a, int b) {
// System.out.print(a + b);
// }
public static void main(String[] args) {
// GatewayServer gatewayServer = new GatewayServer(new test());
// gatewayServer.start();
// System.out.println("Gateway Server Started");
test t = new test();
t.addNumbers(5, 6);
}
}
The outputstream of the executed program test would become the inputstream for your current program run_java_program. Change your code to this and try:
import java.io.IOException;
public class run_java_program {
public static void main(String[] args) {
try {
Process process = Runtime.getRuntime().exec("java -cp C:\\Users\\96171\\eclipse-workspace\\IR_Project\\src test");
java.util.Scanner s = new java.util.Scanner(process.getInputStream());
System.out.println(s.nextLine());
} catch (IOException e) {
e.printStackTrace();
}
}
}
I used Scanner as I know it returns only one line. Based on your need you can also use apache common utils.

How to parse a String that consists of a static method so that we can call it?

I'm trying to write a function that receives a string that consists of a static method with a string array as an argument.
For example, let's imagine we have this class with a static method:
package com.stack.examples;
public class Example {
public static void testMethod() {
System.out.println("method executed");
}
}
Now, our function would be in another class, as follows:
package com.stack.functions;
public class Functions {
public void parseCommand(String command) {
//TODO, this is where my doubts lie
//The given string is always composed of a sequence of Java identifiers
//separated by the character ’.’, representing the full qualified name of
//a Java method (package.class.method)
command.execute(); //Would this work? Perhaps reflection would be ideal
}
}
My objective is to parse the string given as an argument in parseCommand so that
parseCommand("com.stack.examples.Example.testMethod()");
actually calls the static method with the given arguments (in this example case, the method would only print out "message executed").
After searching for alternatives to solve this problem, I found that reflection worked out for me:
Static method to be executed:
package test;
public class Example {
public static void testMethod() {
System.out.println("method executed");
}
}
Main Class:
package test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Main {
public static void reflectVulnerableMethod(String str) throws ClassNotFoundException, NoSuchMethodException, SecurityException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
String[] parts = str.split("\\.");
String forKlazz = "";
for (int i=0; i<parts.length -1; i++) {
if (i != 0){
forKlazz += '.' + parts[i];
}
else forKlazz += parts[i];
}
Class<?> klazz = Class.forName(forKlazz);
Method m = klazz.getMethod(parts[parts.length-1]);
m.invoke(null);
}
public static void main(String[] args) {
try {
reflectVulnerableMethod("test.Example.testMethod");
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
Use Java reflects:
First search for a equaly named method in your Example class and then invoke it.
Maybe also check your Methods parameters method.getParameters()
Method[] methods = Example.class.getMethods();
for (Method method : methods) {
if(method.getName().equals(command)){
try {
method.invoke(Example.class, null);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}

RED5 AXIS camera capturing & streaming

I want to capture an AXIS camera & stream it. I am quite new to RED5. I get the following error:
Exception in thread "main" java.lang.NullPointerException at
org.vikulin.rtmp.publisher.Publisher2.packetReceived(Publisher2.java:23)
at
org.red5.server.presentation.output.flv.FLVStream.dispatchEvent(FLVStream.java:243)
at
org.red5.server.presentation.output.flv.FLVStream.sendAVCDecoderConfig(FLVStream.java:162)
at
org.red5.server.presentation.output.flv.FLVStream.addEvent(FLVStream.java:76) at
org.red5.server.presentation.MediaPresentation.onMediaEvent(MediaPresentation.java:43)
at
org.red5.server.presentation.input.avp.codecs.H264.addPacket(H264.java:206)
at
org.red5.server.presentation.RTSPStream.onRTSPEvent(RTSPStream.java:100)
at
org.red5.server.net.rtsp.proxy.RtspTcp.setupAndPlay(RtspTcp.java:287)
at org.red5.server.presentation.RTSPStream.onSDP(RTSPStream.java:138)
at
org.red5.server.net.rtsp.proxy.RtspTcp.parseDescription(RtspTcp.java:128)
at org.red5.server.net.rtsp.proxy.RtspTcp.describe(RtspTcp.java:64)
at
org.red5.server.presentation.RTSPStream.startInput(RTSPStream.java:77)
at org.red5.server.presentation.RTSPStream.start(RTSPStream.java:82)
at org.vikulin.rtmp.publisher.Publisher2.main(Publisher2.java:49)
Here is the code:
import java.io.IOException;
import org.red5.server.api.stream.IBroadcastStream;
import org.red5.server.api.stream.IStreamListener;
import org.red5.server.api.stream.IStreamPacket;
import org.red5.server.net.rtmp.event.VideoData;
import org.red5.server.presentation.RTSPStream;
import org.red5.server.stream.message.RTMPMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Publisher2 implements IStreamListener {
PublishClient client;
#Override
public void packetReceived(IBroadcastStream arg0, IStreamPacket arg1) {
System.out.println("" + arg1);
VideoData data = new VideoData(arg1.getData());
RTMPMessage message = RTMPMessage.build(data);
try {
client.pushMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException, InterruptedException {
Logger log = LoggerFactory.getLogger(Publisher2.class);
String publishName = "testb";
String host = "127.0.0.1";
int port = 1935;
String app = "live";
PublishClient client = new PublishClient();
client.setHost(host);
client.setPort(port);
client.setApp(app);
client.start(publishName, "live", null);
while (client.getState() != PublishClient.PUBLISHED) {
Thread.sleep(500);
}
Publisher2 test = new Publisher2();
final RTSPStream camera = new RTSPStream("192.168.254.115", 554,
"rtsp://192.168.254.115/axis-media/media.amp?videocodec=h264&videokeyframeinterval=30&fps=30");
camera.addStreamListener(test);
new Thread(new Runnable() {
#Override
public void run() {
camera.start();
}
}).start();
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
camera.stop();
try {//wait for write out.
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
client.stop();
}
}
If you have any idea please help me!
You declared a client variable in your main method, but in your packetReceived method, you reference the class variable. The class variable is still null at that point. So, possibly change this line:
PublishClient client = new PublishClient();
to this:
client = new PublishClient();
or pass the client in to your method, and remove variable declaration from your class.

Instrumentation retransformation doesn't appear to be working

I'm just experimenting with Java Instrumentation because it's very interesting and I'd like to know more about it. I'm using it in conjunction with the javassist library to make bytecode manipulation much easier, and the "tools" library which is included in JDK install.
Here is my main class:
public class MainClass {
public static boolean first = true;
static{
AgentClass.initialize();
}
public static void loadAgent(){
String path = System.getProperty("user.dir") + "\\AgentJar.jar";
String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName();
int p = nameOfRunningVM.indexOf('#');
String pid = nameOfRunningVM.substring(0, p);
try {
VirtualMachine vm = VirtualMachine.attach(pid);
vm.loadAgent(path, "");
vm.detach();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static void main(String[] args){
System.out.println("First run-through, code should be modified once.");
new Hello().hello();
first = false;
try {
AgentClass.getInstrumentation().retransformClasses(Class.forName("test.Hello"));
} catch (Exception e){
e.printStackTrace();
}
System.out.println("Second run-through, code should be modified twice.");
new Hello().hello();
}
}
Here is the "Hello" class:
public class Hello {
public void hello(){
System.out.println("Hello World!");
}
}
Here is the FileTransformer class:
public class FileTransformer implements ClassFileTransformer{
private static boolean first = true;
#Override
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
if (!className.contains("Hello"))
return null;
else{
byte[] result;
CtClass cc = null;
try {
cc = ClassPool.getDefault().get("test.Hello");
CtMethod method = cc.getDeclaredMethod("hello");
if (MainClass.first){
System.out.println("In transformer: first");
method.insertAfter("System.out.println(\"Modified First Time!\");");
}else{
System.out.println("In transformer: second");
method.insertAfter("System.out.println(\"I modified it again.!\");");
}
cc.writeFile();
result = cc.toBytecode();
} catch (Exception e) {
e.printStackTrace();
return null;
}
return result;
}
}
}
The agent class is in another jar, it's a basic implementation of it:
public class AgentClass {
protected static Instrumentation inst;
private static boolean added = false;
public static void agentmain(String args, Instrumentation inst){
AgentClass.inst = inst;
if (!added)
inst.addTransformer(new FileTransformer());
}
public static void premain(String args, Instrumentation inst){
AgentClass.inst = inst;
inst.addTransformer(new FileTransformer());
added = true;
}
public static void initialize(){
if (inst == null){
MainClass.loadAgent();
}
}
public static Instrumentation getInstrumentation(){
return inst;
}
}
When I run, I encounter no errors. However, the output is not how I would expect it to be.
Here is the output I get:
First run-through, code should be modified once.
In transformer: first
Hello World!
Modified First Time!
Second run-through, code should be modified twice.
Hello World!
Modified First Time!
You might notice that there is no line that reads "I modified it again!"
Any help is appreciated.
Not sure if there are any other issues here, but if you want to retransform classes, you need to register the ClassFileTransformer using the method that allows you to specify that the transformer can retransform. i.e.
if you call instrumentation.addTransformer(ClassFileTraIsformer), then you are stating that the transformer does not supports retransforms.
You need to call instrumentation.addTransformer(ClassFileTraIsformer, true) and this will make your transformer kick in.

java.lang.StackOverflowError while using LWJGL's Keyboard class

I have been trying to implement a Keyboard class into my game and received the exception below. This is just a snippet. The full exception goes on for ages longer than this.
Exception in thread "main" java.lang.StackOverflowError
at org.lwjgl.opengl.DisplayMode.<init>(DisplayMode.java:63)
at oregon.client.Oregon.<init>(Oregon.java:10)
at oregon.src.Controller.<init>(Controller.java:9)
at oregon.client.Oregon.<init>(Oregon.java:12)
at oregon.src.Controller.<init>(Controller.java:9)
at oregon.client.Oregon.<init>(Oregon.java:12)
at oregon.src.Controller.<init>(Controller.java:9)
Here's the code for the main class (oregon.client.Oregon):
package oregon.client;
import oregon.src.Controller;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
public class Oregon {
public DisplayMode normal = new DisplayMode(640, 640);
public Controller controls = new Controller();
public boolean fullscreen = false;
public void start() {
try {
create();
} catch (LWJGLException e) {
stop(e);
}
while (!Display.isCloseRequested()) {
events();
Display.update();
}
Display.destroy();
}
public void events() {
try {
controls.getInput();
} catch (LWJGLException e) {
stop(e);
}
}
public void setFullscreen() {
try {
if (!fullscreen) {
Display.setFullscreen(true);
fullscreen = true;
} else if (fullscreen) {
Display.setDisplayMode(normal);
fullscreen = false;
}
} catch (LWJGLException e) {
stop(e);
}
}
public void create() throws LWJGLException {
if (fullscreen) {
Display.setFullscreen(true);
} else if (!fullscreen) {
Display.setDisplayMode(normal);
}
Display.create();
}
public void stop() {
System.exit(0);
Display.destroy();
}
public void stop(Exception e) {
e.printStackTrace();
System.exit(0);
Display.destroy();
}
public static void main(String args[]) {
Oregon oregon = new Oregon();
oregon.start();
}
}
And here's the code for my keyboard class:-
package oregon.src;
import oregon.client.Oregon;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
public class Controller {
public Oregon oregon = new Oregon();
public void getInput() throws LWJGLException {
while (Keyboard.next()) {
if (Keyboard.getEventKeyState()) {
if (Keyboard.getEventKey() == Keyboard.KEY_F11) {
oregon.setFullscreen();
}
}
}
}
}
If there is an expert out the with LWJGL, could you please help me out? Thank you and I hope I do get some help. :D
Nothing to do with LWJGL. Stack overflows in simple code are always because of accidental infinite loops. You have one: Controller tries to create an Oregon (this line: public Oregon oregon = new Oregon();), which then tries to create a Controller, which tries to... (etc..)
When you create an Oregon instance, it creates a Controller instance, which creates an Oregon instance, which creates a Controller instance, which creates an...
What you should probably be doing is not creating an Oregon instance in your controller, but passing your existing instance as a parameter to the Controller constructor and storing that (or the other way around).
Pseudo code:
public Oregon() {
controller = new Controller(this);
...
}
public Controller(Oregon oregon) {
this.oregon = oregon;
...
}

Categories

Resources