Java's built in Scripting engine

Java is a great language … you can work your whole career in it and still not know all of it.
Case in point… I tripped across this tonight and had no idea it even existed…

Anyone ever try to use it to script events in their game?

http://docs.oracle.com/javase/6/docs/technotes/guides/scripting/programmer_guide/#helloworld

edited - corrected typos… too late and not enough caffeine

quick follow up to my original post…

the scripting is pretty awesome so far…

Not sure on performance under load… but what ive managed to do create a script executor and then externalize some of the flow / event scripting of my game.

here is a simple script that changes the current scene in the game after a 5 second delay.
(note: my script executor ensures the script is running in a separate thread)


importPackage(java.lang);
importPackage(com.windpoweredgames.mocha.script);
importPackage(com.windpoweredgames.game.aftermath.scene);
importPackage(com.java);

println("executing script - splash.js");
var scene2 = new SplashScene2();
Thread.sleep(5000);
gameEngine.queueScene(scene2);


I’m definitely going to play with it more and report back on impressions.

I’ve often experimented with scripting in my game but whenever I do it I bind my own classes through the script engine:


ScriptEngine engine = factory.getEngineByName("JavaScript");
engine.put("Name", class);

So if I put in for example java’s System class


engine.put("sys", System);

In javascript you could do


sys.out.println(".....");

It works same, but is just a different way
Good luck with it, I always have found it very powerful!

Beware, it’s an outdated version of Rhino…

Would it be better to download the newer version and just use the jar?
i.e. https://developer.mozilla.org/en-US/docs/Rhino/Download_Rhino?redirectlocale=en-US&redirectslug=RhinoDownload

I have plans to integrate scripting in the engine I’m working on now, but have bigger fish to fry with the code base at the moment. I prefer to use the standalone version of Rhino distributed by Mozilla. Not only is it a newer distribution, as Riven pointed out, it also seems to be more feature rich. I tried out the internal scripting engine over the weekend and was disappointed in the lack of documentation. I couldn’t find a clear cut way to do things such as class shuttering (locking down what Java classes/methods are visible to a script) which may not matter in your scenario, but can be important if you plan to allow users to write custom scripts. There is a little more setup to do with Rhino, but it’s nothing overly complex.

That being said, I’ve got a few work projects that utilize scripting to control application logic and found Rhino to be rock solid in real world use cases. I also recommend considering the approach mentioned by mwarner of exporting only classes that you want to be accessible to the engine. I usually take it one step further and write wrapper classes for the objects that I want to export instead of exporting the core objects directly. It has the advantage of added flexibility in respect to what the scripting environment can access.

Yes. Version 1.7 r4 should be the newest. Just include the js.jar file in your project, and you’re all set.

thanks for the tip… ill check it out :slight_smile:

Nashorn is the very latest Rhino. It’ll be included in java 8:
http://openjdk.java.net/projects/nashorn/

And a funny little javascript + javafx example that I haven’t tried but look interesting:
http://justmy2bits.com/2013/09/08/javafx-with-nashorn-canvas-example/

I thought the whole purpose of scripting was the reduce complexity for the script writer?

That example is line-for-line almost exactly the same as the Java equivalent.

Lol that’s true. I’m a javascript n00b so I actually appreciate the java-styled javascript much better.

The benefit of javascript for me is being able to easily block access by untrusted users to the JVM and server computer, but still allow them to run scripts on my server.

I look forward to being able to take javascript code typed by someone in a browser and execute it on my server without fear that it can trash my Tomcat webserver JVM. For example I could use javascript to call java methods on my server which could fetch data from the database, and manipulate it on the server in javascript and send back the results to the browser.
Or I could allow players in a game to program their own AI in javascript and then execute it on my server in-game.

Using janino (http://docs.codehaus.org/display/JANINO/Home) and real java rather than javascript would be better but I don’t know how to properly restrict access to the sensitive libraries in the JVM from malicious users.
I’ve tried to learn about java’s security policies but everytime I try it seems far too complicated.
I also remember how Riven ran the tiny code program competition and challenged you to hack it and somehow you did. Since Riven overlooked whatever hole you found in his security, I’ve decided to not even try.

But with Nashorn/Rhino/Javascript I can easily block out the dangerous bits of java so there’s no calls to System.exit() etc.

Your classloader can deal with restrictions.

BeanShell2!! You can simply use the java code in it or JS style code, it can run anything!


public int add(int a, int b)
{
    return a+b;
}

Is essentially the same as


add(a, b)
{
    return a+b;
}

And this is how you create the interpreter.


import bsh.Interpreter;

Interpreter i = new Interpreter();

i.source("somefile.bsh");

Hope this helps.

BeanShell is much more popular than Janino for some reason, but I think it’s much worse since it’s slower.
Janino converts code into real java classes that run as fast as any other java code. BeanShell is interpreted and slow.

I don’t know how to restrict classloaders for that purpose, I assume it’s through using SecurityManager which I’m yet to figure out. Also I think that Apache Tomcat (and most java webservers) do their own magic with classloaders which might make it even harder.

Cheers,
keith

You write a custom classloader (based on a janino one in this case) which only allows access to classes you wish to expose.

@CommanderKeith

I use BeanShell because I want to execute the scripts directly, not compile them in which case, I would have used normal Java. Also BeanShell is not slow, it is used in David Brackeen’s book Developing Games in Java and more importantly while creating a 3D software renderer, and the code performed at 70-80 fps on my old laptop with no graphics card.

Janino compiles and runs the script, there’s no disadvantages of using Janino, only the benefit of it being faster.

About your example that ran a 3d game, I doubt the entire game was written in BeanShell or else the FPS would be very low. I’m guessing that BeanShell just called the update method and the rest was done in normal java and openGL, so the bottleneck was not the scripting, in which case it wouldn’t matter what scripting engine you use.

[quote=“CommanderKeith,post:10,topic:45008”]
Don’t draw too many conclusions from that. I decided to do it the easy way at the time, by not allowing capitals in the sourcecode. This did the trick surprisingly well, except that Abuse found a class in the JRE that didn’t adhere to the Java naming conventions and the method call halted the JVM. How lucky he was :slight_smile:

Haha, what a novel approach!

On the topic of locking down code, Google have an interesting library that locks down javascript code run on the client by untrusted third parties: https://code.google.com/p/google-caja/

Yes, I think @SHC is missing the point of Janino. I use it in Praxis LIVE so that users can write custom components on-the-fly, that run at the same speed as anything built in.

Janino does have a disadvantage though, in that you’re pretty much stuck with Java 1.4 source code features. There’s a few things I have planned for the future that might require things like annotations. Now, there is a Janino interface for javac as well, that handles all the in-memory class loading, expression wrapping, etc. - the only problem is that it requires the user to have a JDK.

Hence, I spent yesterday afternoon refactoring javac and the Janino JDK interfaces into a stand-alone compiler lib. Working so far, though a fair bit more testing to do. Weird coincidence this thread! :slight_smile:

In many ways if we’re talking about end-user scripts I’m less concerned about that (unless you’re promoting distribution of course) - let them break their own stuff! I would love to find a good way of controlling things like infinite loops, without adding loads of extra overhead / memory inconsistency.

Sounds like a cool piece of software you built.
It made me think of the eclipse IDE on the floy compiler, would it also be another way of doing what you want? Here’s some details about it:

Ah I see, your application runs on the client’s machine.
I want to run code on my server that the client submits, so I’d like a way to restrict what they can do. I ws reading about SecurityManagers but they seem to restrict the whole JVM. I’ll have to look into Roquen’s suggestion of using ClassLoaders.

About the problem of infinite loops, I was reading a while back that it can be mathematically/logically impossible to tell if a program will ever stop. But I guess by having a timer you could just terminate a thread that ran for too long.