Differences between BSF and JSR 223

Thanks to Yoko’s recent message (http://tinyurl.com/3qwnnu), I was able
to
try out JSR 223 in Java 5 for the first time recently. I noticed some
differences in the way these two engines behave, and I’m wondering if
one of
them is more correct than the other. The included code (see the bottom
of
this message) compares the following Ruby statements when executed as
separate calls to eval():

$x=‘engine_name global’

puts “$x = #{$x}”

x=‘engine_name local’

puts “x = #{x}”

It outputs the following:

$x = bsf global

x = bsf local

$x = sun global

Failed to evaluate: puts “x = #{x}”

javax.script.ScriptException: org.jruby.exceptions.RaiseException

at com.sun.script.jruby.JRubyScriptEngine.evalNode(
JRubyScriptEngine.java:456)

at
com.sun.script.jruby.JRubyScriptEngine.eval(JRubyScriptEngine.java:180)

at
playground.CompareBsfAndSunScopes.evalSun(CompareBsfAndSunScopes.java:35)

at
playground.CompareBsfAndSunScopes.main(CompareBsfAndSunScopes.java:56)

Caused by: org.jruby.exceptions.RaiseException

The failure is caused by x being undefined. It appears top-level local
variables do not remain in scope between repeated calls to the Sun
engine. I
think this makes a lot of sense, but it threw me off because I was not
used
to this behavior from BSF. Is the Sun behavior expected? Is there a way
to
change the calls to BSF to make it behave like the Sun engine for
consistency?

I realize making separate eval() calls like this is probably an unusual
use
case, but it is common in the environment where I am embedding Ruby. I
noticed a few ruby programs I have written under BSF are not working
correctly with the Sun engine. I’m hoping it’s caused by this scope
issue.
I’ll report back if I find out it’s another difference between the
engines.

Also I am wondering if the Sun engine would generally be preferred over
the
BSF engine, since JSR 223 is now a standard part of Java 6. Regardless,
it
seems best to use globals if I need a variable remembered between eval()
calls even though BSF does not require it.

Here’s the code. It works for Java 5 once you put script-api.jar and
jruby-engine.jar on your classpath (see http://tinyurl.com/3qwnnu). On
Java
6, I believe you can
replace com.sun.script.jruby.JRubyScriptEngineManager with
javax.script.ScriptEngineManager,
but I don’t think it’s necessary.

import javax.script.ScriptEngine;
import javax.script.ScriptException;
import org.apache.bsf.BSFException;
import org.apache.bsf.BSFManager;
import com.sun.script.jruby.JRubyScriptEngineManager;

public class CompareBsfAndSunScopes {

BSFManager bsf;
ScriptEngine sun;

public CompareBsfAndSunScopes() {
BSFManager.registerScriptingEngine(“ruby”,
“org.jruby.javasupport.bsf.JRubyEngine”, new String[] { “rb” });
bsf = new BSFManager();
sun = new JRubyScriptEngineManager().getEngineByName(“jruby”);
}

public void evalBsf(String script) {
try {
bsf.eval(“ruby”, “(java)”, 1, 1, script);
}
catch (BSFException e) {
System.err.println("Failed to evaluate: " + script);
e.printStackTrace();
}
}

public void evalSun(String script) {
try {
sun.eval(script, sun.getContext());
}
catch (ScriptException e) {
System.err.println("Failed to evaluate: " + script);
e.printStackTrace();
}
}

public static void main(String args[]) {
CompareBsfAndSunScopes compare = new CompareBsfAndSunScopes();

compare.evalBsf(“$x=‘bsf global’”);
compare.evalBsf(“puts "$x = #{$x}"”);

compare.evalBsf(“x=‘bsf local’”);
compare.evalBsf(“puts "x = #{x}"”);

compare.evalSun(“$x=‘sun global’”);
compare.evalSun(“puts "$x = #{$x}"”);

compare.evalSun(“x=‘sun local’”);
compare.evalSun(“puts "x = #{x}"”);
}
}

–Adam

Hi Adam,

On Tue, Sep 23, 2008 at 12:37 AM, Adam M. [email protected]
wrote:

$x = sun global
at playground.CompareBsfAndSunScopes.evalSun(CompareBsfAndSunScopes.java:35)
consistency?
It is not easy to determine how long local scope should be alive
because Ruby script might have at_exit block in it. To execute at_exit
block, JRuby engine calls JRuby’s terminate method which terminates
local scope like its method name. BSF doesn’t execute at_exit block at
all because BSF doesn’t invoke terminate method. BSF took local scope
to be extended over the eval methods, on the other hand, JRuby engine
took at_exit block to be executed.

I realize making separate eval() calls like this is probably an unusual use
case, but it is common in the environment where I am embedding Ruby. I
noticed a few ruby programs I have written under BSF are not working
correctly with the Sun engine. I’m hoping it’s caused by this scope issue.
I’ll report back if I find out it’s another difference between the engines.

Since JRuby engine is focued on implementing scripting API, JRuby’s
behavior might be different from BSF. However, JRuby engine executes
successfully almost all of test scripts under the test directory which
is included in JRuby’s source archive.

Also I am wondering if the Sun engine would generally be preferred over the
BSF engine, since JSR 223 is now a standard part of Java 6. Regardless, it
seems best to use globals if I need a variable remembered between eval()
calls even though BSF does not require it.

Current JRuby engine’s implementation requires to use global variables
to share variables between Java and Ruby, but it is not a nice idea.
If some alternative way of shareing variables exists, I want to change
it.

Here’s the code. It works for Java 5 once you put script-api.jar and
jruby-engine.jar on your classpath (see http://tinyurl.com/3qwnnu). On Java
6, I believe you can
replace com.sun.script.jruby.JRubyScriptEngineManager with javax.script.ScriptEngineManager,
but I don’t think it’s necessary.

Yes. Using com.sun.script.jruby.JRubyScriptEngineManage is optional.

“org.jruby.javasupport.bsf.JRubyEngine”, new String[] { “rb” });
}
public static void main(String args[]) {
}

–Adam

-Yoko


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Hi.
Let me correct my error and add information.

On Sun, Sep 28, 2008 at 9:12 PM, Yoko H. [email protected] wrote:

$x=‘engine_name global’

think this makes a lot of sense, but it threw me off because I was not used
took at_exit block to be executed.
BSF has terminate() method, which executes at_exit block well. The
problem was javax.script API doesn’t have terminate() method. For
JRuby engine, choice was to terminate always or never terminate. But,
I introduced new System property to control termination into JRuby
engine 1.1.6, and now JRuby engine can keep using local variables.
This version is available to download from
https://scripting.dev.java.net/servlets/ProjectDocumentList?folderID=8848&expandFolder=8848&folderID=0.
Please see my blog entry,
yokolet's notelets: Recent update of JRuby engine,
for detail.

-Yoko

is included in JRuby’s source archive.

import org.apache.bsf.BSFException;
}
try {
compare.evalBsf(“puts "$x = #{$x}"”);

-Yoko


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Hi Yoko,

Thanks for your work on jruby-engine.

I am trying to get v1.1.6 of jruby-engine working with Java 1.5 on
MacOSX10.5.5 with Java 1.5. I have Java 1.6 installed but am testing
this in 1.5.

I have jruby.jar 1.1.5, jruby-engine 1.1.6, and script-api.jar 1.0
installed in my local maven repo.

Here is my modified pom.xml in jruby-engine:

<?xml version="1.0" encoding="UTF-8"?>


4.0.0
com.sun.script.jruby
test
jar
1.0-SNAPSHOT
test
http://maven.apache.org



maven-compiler-plugin
RELEASE

1.5
1.5
UTF-8






junit
junit
3.8.1
test


org.jruby
jruby
1.1.5
runtime


javax.script
script-api
1.0


com.sun.script.jruby
jruby-engine
1.1.6
runtime


Now the compile and ant steps work:

mvn compile
mvn ant:ant

To get the first test to run:

ant EvalTest

I had to move

/System/Library/Java/Extensions/AppleScriptEngine.jar

to:

/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home/lib/ext

sudo mv /System/Library/Java/Extensions/AppleScriptEngine.jar
/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home/lib/ext

The problem is because AppleScriptEngine.jar is compiled by Apple
with Java 1.6 but it is loaded when Java 1.5 uses javax.script.

For more details see:

Confluence
AppleScriptEngine.jar - Google Search

Now I get a NullPointerException running engine.put:

 public static void main(String[] args) throws

FileNotFoundException, ScriptException {
String basedir = System.getProperty(“base.dir”);
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName(“jruby”);

     //give global varibales to runime by context in the super class
     engine.put("who", new String("Ichiro"));

[test]$ ant EvalTest
Buildfile: build.xml

EvalTest:
[echo] [EvalTest]
[java] java.lang.NullPointerException
[java] at
org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:194)
[java] at org.apache.tools.ant.taskdefs.Java.run(Java.java:747)
[java] at
org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:201)
[java] at
org.apache.tools.ant.taskdefs.Java.execute(Java.java:104)
[java] at
org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
[java] at sun.reflect.GeneratedMethodAccessor2.invoke(Unknown
Source)
[java] at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java] at java.lang.reflect.Method.invoke(Method.java:585)
[java] at
org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:105)
[java] at org.apache.tools.ant.Task.perform(Task.java:348)
[java] at org.apache.tools.ant.Target.execute(Target.java:357)
[java] at
org.apache.tools.ant.Target.performTasks(Target.java:385)
[java] at
org.apache.tools.ant.Project.executeSortedTargets(Project.java:1329)
[java] at
org.apache.tools.ant.Project.executeTarget(Project.java:1298)
[java] at
org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
[java] at
org.apache.tools.ant.Project.executeTargets(Project.java:1181)
[java] at org.apache.tools.ant.Main.runBuild(Main.java:698)
[java] at org.apache.tools.ant.Main.startAnt(Main.java:199)
[java] at
org.apache.tools.ant.launch.Launcher.run(Launcher.java:257)
[java] at
org.apache.tools.ant.launch.Launcher.main(Launcher.java:104)
[java] Caused by: java.lang.NullPointerException
[java] at
com.sun.script.jruby.test.EvalTest.main(EvalTest.java:50)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
Method)
[java] at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[java] at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java] at java.lang.reflect.Method.invoke(Method.java:585)
[java] at
org.apache.tools.ant.taskdefs.ExecuteJava.run(ExecuteJava.java:217)
[java] at
org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:152)
[java] … 19 more
[java] — Nested Exception —
[java] java.lang.NullPointerException
[java] at
com.sun.script.jruby.test.EvalTest.main(EvalTest.java:50)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
Method)
[java] at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[java] at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java] at java.lang.reflect.Method.invoke(Method.java:585)
[java] at
org.apache.tools.ant.taskdefs.ExecuteJava.run(ExecuteJava.java:217)
[java] at
org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:152)
[java] at org.apache.tools.ant.taskdefs.Java.run(Java.java:747)
[java] at
org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:201)
[java] at
org.apache.tools.ant.taskdefs.Java.execute(Java.java:104)
[java] at
org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
[java] at sun.reflect.GeneratedMethodAccessor2.invoke(Unknown
Source)
[java] at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java] at java.lang.reflect.Method.invoke(Method.java:585)
[java] at
org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:105)
[java] at org.apache.tools.ant.Task.perform(Task.java:348)
[java] at org.apache.tools.ant.Target.execute(Target.java:357)
[java] at
org.apache.tools.ant.Target.performTasks(Target.java:385)
[java] at
org.apache.tools.ant.Project.executeSortedTargets(Project.java:1329)
[java] at
org.apache.tools.ant.Project.executeTarget(Project.java:1298)
[java] at
org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
[java] at
org.apache.tools.ant.Project.executeTargets(Project.java:1181)
[java] at org.apache.tools.ant.Main.runBuild(Main.java:698)
[java] at org.apache.tools.ant.Main.startAnt(Main.java:199)
[java] at
org.apache.tools.ant.launch.Launcher.run(Launcher.java:257)
[java] at
org.apache.tools.ant.launch.Launcher.main(Launcher.java:104)

Thanks for any suggestions.


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Hi Stephen,

I know this problem. Once, I myself ran into this trouble. This is why
I added JRubyScriptEngineManager class.

On Tue, Nov 4, 2008 at 8:57 AM, Stephen B.
[email protected] wrote:

jar
1.5
test
1.0
Now the compile and ant steps work:
/System/Library/Java/Extensions/AppleScriptEngine.jar

   ScriptEngineManager manager = new ScriptEngineManager();
   ScriptEngine engine = manager.getEngineByName("jruby");

   //give global varibales to runime by context in the super class
   engine.put("who", new String("Ichiro"));

Try

//ScriptEngineManager manager = new ScriptEngineManager();
JRubyScriptEngineManager manager = new JRubyScriptEngineManager();

-Yoko

[java]     at org.apache.tools.ant.taskdefs.Java.run(Java.java:747)
[java]     at
[java]     at

Method)
[java] — Nested Exception —
org.apache.tools.ant.taskdefs.ExecuteJava.run(ExecuteJava.java:217)
[java] at
org.apache.tools.ant.Project.executeTarget(Project.java:1298)

Thanks for any suggestions.


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Mon, Nov 3, 2008 at 7:55 PM, Yoko H. [email protected] wrote:

BSF has terminate() method, which executes at_exit block well. The
problem was javax.script API doesn’t have terminate() method. For
JRuby engine, choice was to terminate always or never terminate. But,
I introduced new System property to control termination into JRuby
engine 1.1.6, and now JRuby engine can keep using local variables.

Yoko,
I just tried this out and it works great for my needs.

In fact, it looks like remembering local variables no longer works
with BSF in JRuby 1.5. So I may be forced to switch to the JRuby
engine in order to upgrade.

Anyone know why the behavior for BSF changed? See the code I posted
earlier in this thread. It no longer works with BSF.

The JRuby engine now works with that code by adding this line
somewhere before the evals:
System.setProperty(“com.sun.script.jruby.terminator”, “off”);

Adam


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Hi Yoko,

Thanks for responding. This next problem may be simple fix also.

Try

//ScriptEngineManager manager = new ScriptEngineManager();
JRubyScriptEngineManager manager = new JRubyScriptEngineManager();

Now this line in EvalTest.java:

JRubyScriptEngineManager manager = new JRubyScriptEngineManager();

results in this security error:

  [echo] [EvalTest]
  [java] java.security.AccessControlException: access denied

(javax.management.MBeanTrustPermission register)
[java] at
java.security.AccessControlContext.checkPermission(AccessControlContext.java:264)
[java] at
java.lang.SecurityManager.checkPermission(SecurityManager.java:568)
[java] at
com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.checkMBeanTrustPermission(DefaultMBeanServerInterceptor.java:1724)
[java] at
com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:335)
[java] at
com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:497)
[java] at
org.jruby.management.BeanManager.register(BeanManager.java:69)
[java] at
org.jruby.management.BeanManager.register(BeanManager.java:29)
[java] at
org.jruby.compiler.JITCompiler.(JITCompiler.java:68)
[java] at org.jruby.Ruby.(Ruby.java:209)
[java] at org.jruby.Ruby.newInstance(Ruby.java:162)
[java] at org.jruby.Ruby.newInstance(Ruby.java:151)
[java] at
com.sun.script.jruby.JRubyScriptEngine.init(JRubyScriptEngine.java:507)
[java] at
com.sun.script.jruby.JRubyScriptEngine.(JRubyScriptEngine.java:102)
[java] at
com.sun.script.jruby.JRubyScriptEngine.(JRubyScriptEngine.java:98)
[java] at
com.sun.script.jruby.JRubyScriptEngineFactory.getScriptEngine(JRubyScriptEngineFactory.java:134)
[java] at
com.sun.script.jruby.JRubyScriptEngineManager.registerEngineNames(JRubyScriptEngineManager.java:95)
[java] at
com.sun.script.jruby.JRubyScriptEngineManager.init(JRubyScriptEngineManager.java:72)
[java] at
com.sun.script.jruby.JRubyScriptEngineManager.(JRubyScriptEngineManager.java:66)
[java] at
com.sun.script.jruby.JRubyScriptEngineManager.(JRubyScriptEngineManager.java:61)
[java] at
com.sun.script.jruby.test.EvalTest.main(EvalTest.java:48)

Normally I am not running under a restricted security policy. Is this
set by the ant script somehow?


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Hi Stephen,

I updated samples included in jruby-engine-1.1.6.tar.gz or zip
archives. The updated archives are at
https://scripting.dev.java.net/servlets/ProjectDocumentList?folderID=8848&expandFolder=8848&folderID=8848.
I tested samples on JDK 1.5 and got correct outputs, so probably you
don’t have exceptions anymore. Please read README.txt in the test
directory when you try samples. An archive of jruby-engine is now in
java.net’s maven repo, so you need to install JSR 223 API’s archive
only. Don’t forget to use JRubyScriptEngineManager if you try them on
OS X that has both JDK 5 and 6.

-Yoko

On Tue, Nov 4, 2008 at 12:08 PM, Stephen B.
[email protected] wrote:

java.lang.SecurityManager.checkPermission(SecurityManager.java:568)
[java] at org.jruby.compiler.JITCompiler.(JITCompiler.java:68)
com.sun.script.jruby.JRubyScriptEngineFactory.getScriptEngine(JRubyScriptEngineFactory.java:134)
Normally I am not running under a restricted security policy. Is this set by
the ant script somehow?


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Tue, Nov 4, 2008 at 12:08 PM, Stephen B.
[email protected] wrote:

JRubyScriptEngineManager manager = new JRubyScriptEngineManager();

results in this security error:

[echo] [EvalTest]
[java] java.security.AccessControlException: access denied

(javax.management.MBeanTrustPermission register)

I guess this would be a maven related trouble. When I tried this
example mannually,

cd /Users/yoko/Works/jruby-engine-1.1.6/test
java -Dbase.dir=.
-cp
target/classes:/Users/yoko/Tools/jruby-1.1.5/lib/jruby.jar:…/lib/jruby-engine.jar:/Users/yoko/Works/jsr223/script-api.jar

com.sun.script.jruby.test.EvalTest

I got expected output. I tried to run these examples via maven but
failed because of a different exception from yours.
I haven’t checked examples and pom.xml under test directory for a long
time, those might be outdated. I’m going to work on this and report
later when I figure out what is wrong with that.

-Yoko

[java]     at

com.sun.script.jruby.JRubyScriptEngine.(JRubyScriptEngine.java:102)
[java] at


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

OS X that has both JDK 5 and 6.

-Yoko

Thank you very much Yoko.

The maven compile process had very strange errors where it claimed
that it couldn’t resolve the dependency to script-api – even though
it was installed correctly in my local repository.

Running mvn -X compile showed maven trying to download an incorrect
dependency specification for script-api and failing.

After I replaced the existing v1.1.6 jruby-engine.jar in my local
maven repository with the new one from the archive the compile and
test worked.

mvn install:install-file -DgroupId=com.sun.script.jruby
-DartifactId=jruby-engine -Dversion=1.1.6 -Dpackaging=jar
-Dfile=jruby-engine-1.1.6/lib/jruby-engine.jar

I must have somehow created a corrupted dependency specification in
the past associated with earlier attempts to build/install
jruby-engine-1.1.6 …

Now I’ll get back to my own tests :wink:


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email