unperformant

bsf.jar

commons-logging-1.1.jar

js.jar

hello_javascript

hello_javascript

hello_javascript\lib

bsf.jar

commons-logging-1.1.jar

js.jar

lib

hello_javascript\lib\bsf.jar

hello_javascript\lib\commons-logging-1.1.jar

hello_javascript\lib\js.jar

HelloJavascript.java

hello_javascript\com\raganwald\public\HelloJavascript.java

package com.raganwald.public;



import org.apache.bsf.BSFManager;



public class HelloJavascript {

public static void main (final String[] argv) {

final BSFManager manager = new BSFManager();

final Object jso = manager.eval("javascript", "(java)", 1, 1, "'hello, Javascript'");

System.out.println(jso.toString());

}

}



manager.eval(

"javascript", "(java)", 1, 1,

"var f = function (what) { return 'hello, ' + what; }; f('Javascript);");



javascript

hello_javascript\javascript

import org.apache.bsf.util.IOUtils;



// ...



static String readScript(final String fileName) throws Exception {

final FileReader in = new FileReader(fileName);

return IOUtils.getStringFromReader(in);

}



Set





Prototype and Scriptaculous are the Javascript libraries that make slick transitions and UI effects easy one-liners. Prototype does more than just make an application look good: it adds Ruby and Smalltalk-like methods for handling Hashes, Arrays, and the DOM.



This book is one of the fastest ways to get up to speed on taking Javascript to the next level.



manager.eval("javascript", "(java)", 1, 1,

"myJavascriptFunction(" + myJSONString + ");");



XMLHttpRequest

import org.mozilla.javascript.NativeArray;

import org.mozilla.javascript.ScriptableObject;



import java.util.ArrayList;

import java.util.Arrays;

import java.util.HashMap;

import java.util.List;

import java.util.Map;



// ...



static List unwrapNativeArray (final NativeArray na) {

return new ArrayList<Object> () {{

for (int i = 0; i < na.getLength(); ++i) {

add(unwrapNative(na.get(i, null)));

}

}};

}



static List unwrapPrototypeArray (final ScriptableObject sObj) {

return new ArrayList<Object> () {{

final List<Object> sObjIds = Arrays.asList(sObj.getAllIds());

for (int i = 0; sObjIds.contains(i); ++i) {

add(unwrapNative(sObj.get(i, null)));

}

}};

}



static Map unwrapObject (final ScriptableObject sObj) {

return new HashMap<String, Object> () {{

for (Object id: sObj.getAllIds()) {

put(id.toString(), unwrapNative(sObj.get(id.toString(), null)));

}

}};

}



static Object unwrapNative (final Object obj) {

if (obj instanceof NativeArray) {

return unwrapNativeArray((NativeArray) obj);

}

else if (obj instanceof ScriptableObject) {

final ScriptableObject sObj = (ScriptableObject) obj;

final List<Object> sObjIds = Arrays.asList(sObj.getAllIds());

if (sObjIds.contains("keys")) { // a prototype enumerable/hash

return unwrapObject(sObj);

}

else if (sObjIds.contains("flatten")) { // a prototype enumerable/array

return unwrapPrototypeArray(sObj);

}

else return unwrapObject(sObj);

}

else return obj;

}



This post is about executing Javascript inside the JVM without using a browser. Besides the fact that people are talking about running Javascript on the server again , and again ), here’s why my colleagues and I used it on a recent project:We have some logic that needs to run on the server and on the client, depending on when the application applies it. There is like an incredibly complex form validation involed. Think of a loan application, for example. Zillions of rules like “at least five years at current location or at most three locations in ten years or owns current location for at least one year.” The whole thing forms a big logical expression that needs to be evaluated in such a way that we can report which pieces are missing or do not meet requirements (Declined because income is insufficient and does not state purpose of loan).There are a couple of ways to handle this. One is to submit the form back to the server for validation. Another is to write everything in Java, but use a sophisticated tool to render the Java into Javascript . Naturally, our team chose a third option, The Rails Way (available for pre-order ).We have a Domain-Specific Language for describing the rules. Business users use the DSL, and another tool writes code from that. We could, in theory, write Java methods for the server and write Javascript for the client. We chose to start with Javascript, and we’ll write Java for the server if running Javascript on the server turns out to beslow.In the mean time, we decided that having some Java make a simple function call to a Javascript function and process a simple result was a reasonable first step. As a side benefit, we run all our server-side Javascript unit tests in Java test suites alongside our Java unit tests.And after some fiddling around, we got Javascript working on the JVM. My bet is that you can get it working too, and it won’t take more than fifteen minutes.Care to try it?You’ll need JDK 1.5 or 1.6 from Sun. If you already have this, move on to step one. Still reading? You’ll need to do a big install before we go further.Go to the downloads page and download the latest thing they have on offer with the words “JDK” in it. You won’t need JEE (the framework formerly known as J2EE) for this exercise, but if you know what it is you know enough to decide whether to download it.Right now, you want. Go get it and suffer through the installation process.Java6 has a new framework for running “scripting” languages, and it’s built into Java6. We’re not going to use it today, just because some of you may still need to make stuff work with JDK 1.5 in production. Instead, we’re going to go get the Jakarta Bean Scripting Framework (BSF). You can download it here . We’ll needYMMV, but I found that I couldn’t get BSF working without including the Jakarta Commons-Logging jar. So if you don’t have this floating around, go here and download it. I experimented, and I could ignore everything except. If that was missing, BSF kakked.Since we’re going to run Javascript, we need an interpreter. Rhino to the rescue. Download it . We’ll needReady to code? Let’s start with a directory for all of our stuff. Call it. For the sake of keeping thing simple, set up the sub-structure as follows:You may be using a fancy IDE, you may be using a text editor and have to graft your classpaths together with chicken wire. The important thing is that your classpath, besides including all of Java’s required stuff, and your own Java classes, also includesandWe’ll put all three in thesubdirectory:Let’s write some Java: create the following subdirectories and put a file calledin it:Let’s give it some code:Run your new Java application. Did you see that? It interpreted some Javascript in the JVM without a browser. Check your watch. Did you need more than a quarter of an hour? I didn’t think so.You can try more ambitious code:I didn’t find an easy way to get Javascript files to include other Javascript files. This isn’t the worst thing in the world, but you certainly don’t want to write anything substantial inside of Java strings. So try experimenting with reading javascript files right off the classpath.I created a subdirectory calledAnd you can read Javascript into your strings or Stringbuffers with some fairly simple code, thanks to a utility built into BSF:That reads some script into a string. You can then prepend it to whatever you want to evaluate. Note that if you want to set up some sort of simple checking to make sure that you don’t “include” the same file twice, you will need to write yourself a little framework for that, perhaps using ato keep track of what you’ve already loaded.This is nice, and with a little work you could make a program that reads paths to Javascript files off the commend line and executes them. But to make things really interesting, you want to find a way to get Java data into your JavaScript and do something useful with the results, not just print it as a String.BSF provides a way to inject objects into the scripting language’s environment, so you could use that facility. When writing automated unit tests for that particular project, I chose a simpler route: I serialized the data into JSON and used that to call a Javascript function directly via BSF:This is a really bad idea if your JSON is handed you from an insecure source, such as a public web page calling you back via, but if you trust your source, this works wonderfully.Now what do you do with the result? If you are generating something esoteric like a Javascript function, I have no idea. In my own case, I return all values as simple trees of Hashes (Javascript objects without any special methods) and Arrays. I convert those into Java trees of Maps and Arrays:Check your watch. Are you still under fifteen minutes? Great!

Labels: lispy, popular