Monday, April 28, 2008

Invocable#getInterface with two interfaces

I wonder that even though multiple Java interfaces are mixed in and implemented by Ruby, whether only one invocation of getInterface method would be enough or not. To figure out what would happen, I wrote two interfaces below:
package mountainash;

public interface FlowerAttribute {
String getName();
String getColor();
double getPrice();
}

package mountainash;

public interface Flowers {
FlowerAttribute selectFlower(String name, String color);
}
Then, I wrote Ruby script implementing above interfaces like this:
# 
# Florist.rb

require 'java'

class Flower
import 'mountainash.FlowerAttribute'
def initialize(name, color, price)
@name = name
@color = color
@price = price
end
def getName
@name
end
def getColor
@color
end
def getPrice
@price
end
end

class Florist
import 'mountainash.Flowers'
def initialize
@list = [Flower.new("rose", "red", 1.99),
Flower.new("rose", "pink", 1.59),
Flower.new("tulip", "red", 0.99),
Flower.new("tulip", "pink", 1.09)]
end
def selectFlower(name, color)
@list.each { |flower| if flower.getName == name &&
flower.getColor == color
then return flower end }
end
end
Florist.new
After evaluating the script and invoking getInterface method, we will get just one mountainash.Flowers type object in Java code.
Object obj = parsedScript.eval(scriptContext);
Flowers flowers = ((Invocable)engine).getInterface(obj, Flowers.class);
Do we need to use getInterface method again to get FlowerAttribute type object, like this?
Object obj2 = flowers.selectFlower(name, color);
FlowerAttribute attribute = ((Invocable)engine).getInterface(obj2, FlowerAttribute.class);
The answer was no. In this case, just one invocation of getInterface method worked perfect.
Object obj = parsedScript.eval(scriptContext);
Flowers flowers = ((Invocable)engine).getInterface(obj, Flowers.class);
FlowerAttribute attribute = flowers.selectFlower("rose", "red");

However, I haven't tested every possible case, there might be cases getInterface method needs to be invoked multiple times. Or, older version of JRuby might have caused some trouble. I tested this on JRuby 1.1.1 and didn't have any problem.

The entire code I tried is:
package mountainash;

import java.io.*;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleScriptContext;
import javax.servlet.*;
import javax.servlet.http.*;

public class FloristServlet extends HttpServlet {

private ScriptEngine engine;
CompiledScript parsedScript;

@Override
public void init() {
try {
ScriptEngineManager manager = new ScriptEngineManager();
engine = manager.getEngineByName("jruby");

ClassLoader loader = getClass().getClassLoader();
InputStream iStream = loader.getResourceAsStream("ruby/Florist.rb");
Reader reader = new InputStreamReader(iStream, "UTF-8");
parsedScript = ((Compilable) engine).compile(reader);
} catch (ScriptException ex) {
Logger.getLogger(FloristServlet.class.getName()).log(Level.SEVERE, null,
ex);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(FloristServlet.class.getName()).log(Level.SEVERE, null,
ex);
}
}

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
SimpleScriptContext scriptContext = new SimpleScriptContext();
scriptContext.setWriter(out);
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet FloristServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h3>Servlet FloristServlet at " + request.getContextPath() + "</h3>");
out.println("<pre>");
Object obj = parsedScript.eval(scriptContext);
Flowers flowers = ((Invocable)engine).getInterface(obj, Flowers.class);
FlowerAttribute attribute = flowers.selectFlower("rose", "red");
out.print(getString(attribute));
out.println("<br/>");
attribute = flowers.selectFlower("rose", "pink");
out.print(getString(attribute));
out.println("<br/>");
attribute = flowers.selectFlower("tulip", "red");
out.print(getString(attribute));
out.println("<br/>");
attribute = flowers.selectFlower("tulip", "pink");
out.print(getString(attribute));
out.println("</pre>");
out.println("</body>");
out.println("</html>");
} catch (ScriptException ex) {
Logger.getLogger(FloristServlet.class.getName()).log(Level.SEVERE, null, ex);
} finally {
out.close();
}
}

private String getString(FlowerAttribute attribute) {
return attribute.getName() +
"(" + attribute.getColor() +
") : $" + attribute.getPrice();
}

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
}
Mountainash web application directory hierarchy is below:
+ Mountainash
+ WEB-INF
+ src
+ mountainash
- FloristServlet.java
- FlowerAttribute.java
- Flowers.java
+ ruby
- FLorist.rb
+ lib
- jruby.jar
- jruby-engine.jar
- script-api.jar
+ classes -+
+ mountainash | automatically created
- FloristServlet.class | directories and files
- FlowerAttribute.class | by IDE
- Flowers.class |
+ ruby |
- Florist.rb -+
Correct output from FloristServlet will be:
<html>
<head>
<title>Servlet FloristServlet</title>
</head>
<body>
<h3>Servlet FloristServlet at /Mountainash</h3>
<pre>
rose(red) : $1.99<br/>
rose(pink) : $1.59<br/>
tulip(red) : $0.99<br/>
tulip(pink) : $1.09</pre>
</body>
</html>

Friday, April 18, 2008

JRuby engine for JDK 1.5

I've released JSR 223 JRuby engine for JDK 1.5 the other day. New release includes JRubyScirptEngineManager class, which is alternative to javax.script.ScriptEngineManager for JDK 1.5 users. However, newly added class was not necessary for JDK 1.5 users. NetBeans tricked me.

When I tested JRuby engine on JDK 1.5, I could not avoid version mismatch error caused by some archives compiled on JDK 1.6. I thought this must have come from script-api.jar which is distributed in a binary form. The archive was the only one that considerably compiled on JDK 1.6. JAVA_HOME was set to 1.5, commend, java -version, ouputs version 1.5 correctly, etc/netbeans.conf has correct path to JDK 1.5, and the project on NetBeans has 1.5 library only. However, script-api.jar was not a culprit. It was NetBeans trick. NetBeans has cached old classpath to 1.6 of the project and never refreshes it. Caches are in directories under /Users/yoko/.netbeans/6.1beta/var/cache/index/0.8. My JDK 1.6 for Mac OSX has JSR 223 AppleScript engine in it and causes version mismatch error. Even though NetBeans works on JDK 1.5, and the project has JDK 1.5 library only, cached classpath to JDK 1.6 is vaild for execution. Very tricky. The old cached classpath is not valid for compile, so I got compile error if I did not have script-api.jar in the project library.

Although JRubyScriptEngineManager does not need for JDK 1.5, this class helped me to figure out what's going on. Moreover, I added relevant exception which would help users keep from stucking into. javax.script.ScriptEngineManager does not raise any exception even though it could not find script engine. People often don't know null is returned and got exception at the eval() method line. JRubyScriptEngineManager might help users out.

Monday, April 07, 2008

Tips for JRuby engine: Sites to learn about scripting API

For the eighth post of "Tips for JRuby engine" series I've written in this blog, I'll introduce useful sites to learn about JSR 223 scripting API.

Tips for JRuby engine: Compilable and CompiledScript usage

This is the seventh post of "Tips for JRuby engine" series I've written in this blog and shows how to use Compilable interface and CompiledScript class defined in JSR 223 scripting API, and why they are useful. These two APIs are used when programmers want to just parse scripts without evaluating them. Once the script has been parsed, programmers can evaluate it continuously as many times as they need without parsing. This mechnism is useful especially for web applications because we don't want to parse scripts for every http request after debugging has completed. We want to just evaluate them to process each http request. When scripting and Servlet APIs are put together, we could receive benefit of Compilable and CompiledScript APIs fully.

Let's look at an example program:
package mountainash;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleScriptContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CompilableTestServlet extends HttpServlet {

private ScriptEngine engine;
CompiledScript parsedScript, parsedScript2;

@Override
public void init() {
try {
ScriptEngineManager manager = new ScriptEngineManager();
engine = manager.getEngineByName("jruby");

ClassLoader loader = getClass().getClassLoader();
InputStream iStream = loader.getResourceAsStream("ruby/simple2.rb");
Reader reader = new InputStreamReader(iStream, "UTF-8");
parsedScript = ((Compilable) engine).compile(reader);

iStream = loader.getResourceAsStream("ruby/simple3.rb");
reader = new InputStreamReader(iStream, "UTF-8");
parsedScript2 = ((Compilable) engine).compile(reader);
} catch (ScriptException ex) {
Logger.getLogger(CompilableTestServlet.class.getName()).log(Level.SEVERE, null, ex);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(CompilableTestServlet.class.getName()).log(Level.SEVERE, null, ex);
}
}

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
SimpleScriptContext scriptContext = new SimpleScriptContext();
scriptContext.setWriter(out);

try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet CompilableTestServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h3>Servlet CompilableTestServlet at " + request.getContextPath() + "</h3>");
out.println("<pre>");
parsedScript.eval(scriptContext);
out.println("<br/>");
parsedScript2.eval(scriptContext);
out.println("</pre>");
out.println("</body>");
out.println("</html>");
} catch (ScriptException ex) {
Logger.getLogger(CompilableTestServlet.class.getName()).log(Level.SEVERE, null, ex);
} finally {
out.close();
}
}

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

@Override
public String getServletInfo() {
return "JRuby engine test: use Compilable interface";
}
}

--------------------

# simple2.rb

puts "Compilable interface test"
puts "できたかな?"

--------------------

# simple3.rb

def greetings(to)
puts "Good morning, #{to}!"
end

greetings("glassfish")
greetings("grasshopper")
greetings("みなさん")
This servlet parses two Ruby scripts in its init() method, then, evaluated in its processRequest() method. This means that two scripts are parsed only once when the servlet is loaded onto a servlet container and are just evaluated everytime http request occurs. Two APIs, Compilable and CompiledScript, would contribute to improve performance of web applications. The busier the web application is, the more we can expect performance improvement because processing time for parsing is eliminated.

To try this example, please see my former post to know bases.

Here's a web application directory hierarchy:

+ Mountainash
+ WEB-INF
+ src
+ mountainash
- SimpleServlet.java
- CompilableTestServlet.java
+ ruby
- simple.rb
- simple2.rb
- simple.rb
+ lib
- jruby.jar
- jruby-engine.jar
+ classes -+
+ mountainash | automatically created
- SimpleServlet.class | directories and files
- CompilableTestSErvlet.class | by IDE
+ ruby |
- simple.rb |
- simple2.rb |
- simple3.rb -+
When this servlet gets run successfully, we get the following output:
<html>
<head>
<title>Servlet CompilableTestServlet</title>
</head>
<body>
<h3>Servlet CompilableTestServlet at /Mountainash</h3>
<pre>
Compilable interface test
できたかな?
<br/>
Good morning, glassfish!
Good morning, grasshopper!
Good morning, みなさん!
</pre>
</body>
</html>

Well, the names, Compilable and CompiledScript, are confusing for JRuby users. JRuby has a feature to compile Ruby script to create Java bytecode. Perhaps, Parsable and ParsedScript would be more understandable names.

Saturday, April 05, 2008

Tips for JRuby engine: servlet meets JRuby engine

This is the sixth post of "Tips for JRuby engine" series I've written in this blog and shows how to get started writing servlet code using JSR 223 scripting API. Scripting API are smoothly mixed into other APIs since it is a part of standard Java APIs. Using JSR 223 scripting and Servlet APIs, we can make web applications more easily and delightfully thanks to the power of dynamic languages. However, programmers should be careful to use classes an interfaces of scripting API. Scripting API considers to be run on a servlet though not perfect, while implementations of dynamic languages often have some flaws for servlet style concurrent programming. Once scripting API works togther with Servlet API, multiple threads execute a single method of a single instance concurrently. How about JRuby implementation? It is not basicaly compliant to the servlet style, concurrent invocation. For example, JRuby's runtime has only one instance of GlobalVariables which is used to share instances between Java applications and JRuby and might cause a race condition when it executes consecutive mutilple evaluations on its single runtime. Thus, I'll write about what programers should take into account to write a servlet code effectively, a couple of times in this blog.

Firstly, I'll start with a very simple servlet. It just shows simple messages after executing a hello-world script written in Ruby. Tediously simple, but important to make sure that scripting APIs work on a servlet container. Because Servlet API and its web application require a specific directory structure, and adopt their own classloading mechanism, we need to fit scripting API in to a servlet based web application. Unless, some of programmers might experience hard time for the frist servlet code in action.

Before start writing the code, we must set up two jar archives, jruby.jar and jruby-engine.jar, to the right place. It is WEB-INF/lib. Most programmers use some sort of IDE and probably know about how to set up these two archives in a web application. I'm a NetBeans user, so I clicked on Libraries > Add JAR/Folder menu of a web project, and added them.

Here are the simple servlet and Ruby script:
package mountainash;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;

import java.io.Reader;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleScriptContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class SimpleServlet extends HttpServlet {

private ScriptEngine engine;

@Override
public void init() {
ScriptEngineManager manager = new ScriptEngineManager();
engine = manager.getEngineByName("jruby");

}

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
SimpleScriptContext scriptContext = new SimpleScriptContext();
scriptContext.setWriter(out);

try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet SimpleServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h3>Servlet SimpleServlet at " + request.getContextPath() + "</h3>");
out.println("<pre>");
ClassLoader loader = getClass().getClassLoader();
Reader reader =
new InputStreamReader(loader.getResourceAsStream("ruby/simple.rb"), "UTF-8");
engine.eval(reader, scriptContext);

out.println("</pre>");
out.println("</body>");
out.println("</html>");
} catch (ScriptException ex) {
Logger.getLogger(SimpleServlet.class.getName()).log(Level.SEVERE, null, ex);
} finally {
out.close();
}
}

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

@Override
public String getServletInfo() {
return "JRuby Engine Test: very simple";
}
}

--------------------

# simple.rb

puts "Hello World from Ruby over JRuby engine"
puts "こんにちは世界"
Lines colored red have scripting APIs mixed in to this servlet. In a init() method, the servlet gets JRuby engine's instance, which means that this servlet has only one JRuby runtime to process multiple requests rushed to this servlet all at once. Also, only one instance of JRuby engine takes care of multiple http requests concurrently. This is why this servlet doesn't use engine.put() or engine.setWriter() methods not to be suffered from a race condition. Instead, this servlet creates SimpleScriptContext type instance for each http request to share objects with Ruby script.

Where do I put Ruby scripts? This question might come up since everything should be in Java's web application directory structure. The way of getting scripts depends on where are they. We can take scripts in the servlet either specifing the file path relative to the web application's context root or reading the file as a resource by using a class loader. This servlet uses the latter one, so Ruby scripts must be in the WEB-INF/lib or WEB-INF/classes directory, or subdirectories of WEB-INF/classes, which are available for web application's class loader to load resources. Again, I'm a NetBeans user, so I created the folder whose name is ruby under the Source Packages folder and put the script there. Then, NetBeans copied it to build/web/WEB-INF/classes/ruby directory automatically, consequently, the script became loadable.
Mountainash project's directory hierarcy

+ Mountainash
+ WEB-INF
+ src
+ mountainash
- SimpleServlet.java
+ ruby
- simple.rb
+ lib
- jruby.jar
- jruby-engine.jar
+ classes -+
+ mountainash | automatically created
- SimpleServlet.class | directories and files
+ ruby |
- simple.rb -+

When this servlet gets run successfully, we get the following output:
<html>
<head>
<title>Servlet SimpleServlet</title>
</head>
<body>
<h3>Servlet SimpleServlet at /Mountainash</h3>
<pre>
Hello World from Ruby over JRuby engine
こんにちは世界
</pre>
</body>
</html>

Tuesday, April 01, 2008

Tips for JRuby engine: getInterface() usage

This is the fifth post of "Tips for JRuby engine" series I've written in this blog and shows how to use javax.script.Invocable#getInterface() method defined in JSR 223 APIs. This method is used when Ruby scripts provide implementations of Java defined interfaces. In other words, JSR 223 API allows us to write interfaces only in Java and implement them by Ruby. A programmer can discover interface-implemented, Ruby-created instances by using getInterface() method and invoke methods defined in the interfaces.

JSR 223 API defines two types of getInterface() method - <T> T getInterface(Class<T> clasz), and <T> T getInterface(Object thiz, Class<T> clasz). The difference of these two methods is similar to the one between invokeFunction() and invokeMethod(). While the former method is applied to the top-level methods, the latter is done to the methods defined in classes or modules. Likewise, <T> T getInterface(Class<T> clasz) is used when interface-defined methods are implemented by Ruby's top-level methods, and <T> T getInterface(Object thiz, Class<T> clasz) is for methods that Ruby scripts implemented in classes or modules.

If programmers want to implement Java interface by Ruby, they need at least two statements in Ruby script - first, require 'java': second, include_class for top-level methods, or import for others to claim that the script is the implementation of some interfaces. Suppose the interface below has defined:
package canna;

import java.util.List;

public interface SimpleFile {
void create(String filename);
void write(List list);
void close();
}
When the programmers implement this interface by Ruby's top-level methods, Ruby script would be like this:
require 'java'
include_class 'canna.SimpleFile'
def create(name)
@name = name;
@tmpfile = File.new(name, "w");
@tmpfile.chmod(0600);
end
def write(message)
message.each { |m| @tmpfile.puts(m) }
end
def close()
@tmpfile.close;
puts "The file, #{@name}, has #{File.size(@name)} bytes."
end
Thie script has require 'java' and include_class 'canna.SimpleFile' statements in the beginning to load Java extension and to include Java interface, then defines create, write, and close methods that the interface, canna.SimpleFile, has. In case of top-level methods' implementation, script doesn't need to return any instance since JRuby engine gets a receiver object, "self," from JRuby's runtime internally. Utilizing Ruby's implementation, Java code would be:
engine.eval(script);
Invocable invocable = (Invocable) engine;
SimpleFile simpleFile = invocable.getInterface(SimpleFile.class);
simpleFile.create("simplefile.txt");
List list = new ArrayList();
list.add("A bird in the hand is worth two in the bush.");
list.add("Birds of a feather flock together.");
list.add("Every bird loves to hear himself sing.");
simpleFile.write(list);
simpleFile.close();

Once, we run this code, we'll find the file whose name is simlefile.txt in file system and see three lines in it. As we expect, simplfile.txt has the mode 0600:
-rw-------   1 yoko  staff   119  4  2 14:06 simplefile.txt

How should the programmers write a code if they want to implemment Java interfaces by defiening Ruby classes? The Ruby script must have require 'java' statement prior to a class definition, and import 'canna.SimpleFile' statement in a class definition. Besides, the script must return more than one instance. Thus, it would look like:
require 'java'
class SimpleFileImple
import 'canna.SimpleFile'
def initialize(name)
@name = name;
@tmpfile = File.new(name, "w");
@tmpfile.chmod(0600)
end
def write(message)
message.each { |m| @tmpfile.puts(m) }
end
def close()
@tmpfile.close;
puts "The file, #{@name}, has #{File.size(@name)} bytes."
end
end
SimpleFileImple.new($name)
SimpleFileImple class implements Java-defined canna.SimpleFile interface, and has a constructor, and write and close methods definition, but not create method. Ruby doesn't complain that not all methods of the interface imported are covered. Then, Java code would be written below:
engine.put("name", "simplefile2.txt");
Object object = engine.eval(script);
Invocable invocable = (Invocable) engine;
SimpleFile simpleFile = invocable.getInterface(object, SimpleFile.class);
List list = new ArrayList();
list.add("When it is a question of money, everybody is of the same religion.");
list.add("Money is the wise man's religion.");
simpleFile.write(list);
simpleFile.close();
This code gets java.lang.Object typed instance when the Ruby script is evaluated. This instance must be created by Ruby and is able to be casted into canna.SimpleFile type, or getInterface() method doesn't work correctly. The argument of the constructor, which is a file name, is passed by using a global variable name, so simplefile2.txt will appear after the code gets run.

At last, I'll demonstrate more complicated but more real example. In a real application, people often implement more than one interface in a single class, and instantiate mutiple objects based on the single definition. To see how to do this, let's create very simple two interfaces, canna.Remarkable and canna.Removable, shown below:
package canna;

public interface Remarkable {
void remark();
}

package canna;

public interface Removable {
void remove(int i);
}
Then, think about what the Ruby script would be. We need to have require 'java' and two import statements in it, plus, methods' implementations; moreover, we are going to create and return two instances to give over to Java. Considering these requirements, we would write following Ruby script to wrap them up.
require 'java'
class Flowers
import 'canna.Remarkable'
import 'canna.Removable'
@@hash = {'red' => 'ruby', 'white' => 'pearl'}
def initialize(color, names)
@color = color;
@names = names;
end
def remark
puts "#{@names.join(', ')}. Beautiful like a #{@@hash[@color]}!"
end
def remove(index)
print "If I remove #{@names[index]}, ";
@names.delete_at(index);
print "others will be #{@names.join(', ')}."
end
end
red = Flowers.new("red", ["cameliia", "hibiscus", "rose", "canna"])
white = Flowers.new("white", ["gardenia", "lily", "magnolia"])
return red, white
When this script is evaluated, we'll get a java.util.List type object that has multiple return values in its elements. Therefore, in Java code, we would take each instance out from the List type object, and invoke methods defined in the interfaces, like this:
Object objects = engine.eval(script);
Invocable invocable = (Invocable) engine;
if (objects instanceof List) {
for (Object object : (List)objects) {
Object flower = invocable.getInterface(object, Remarkable.class);
((Remarkable)flower).remark();
flower = invocable.getInterface(object, Removable.class);
((Removable)flower).remove(1);
}
}


This is an interesting feature of JSR 223 APIs; however, old versions of JRuby had a problem to execute getInterface() method correctly. Make sure your JRuby is 1.1RC2 or later.

Here are entire codes to perform all snippets I mentioned here:
//Remarkable.java
package canna;

public interface Remarkable {
void remark();
}

//Removable.java
package canna;

public interface Removable {
void remove(int i);
}

//GetInterfacesExample.java
package canna;

import java.util.ArrayList;
import java.util.List;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class GetInterfacesExample {
private GetInterfacesExample() throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
getInterfaceByTopLevel(engine);
getInterfaceByClass(engine);
getInterfaceMultipleStuffs(engine);
}

private void getInterfaceByTopLevel(ScriptEngine engine) throws ScriptException {
String script =
"require \'java\'\n" +
"include_class \'canna.SimpleFile\'\n" +
"def create(name)" +
"@name = name;" +
"@tmpfile = File.new(name, \"w\");" +
"@tmpfile.chmod(0600);" +
"end\n" +
"def write(message)" +
"message.each { |m| @tmpfile.puts(m) }" +
"end\n" +
"def close()" +
"@tmpfile.close;" +
"puts \"The file, #{@name}, has #{File.size(@name)} bytes.\"" +
"end";

engine.eval(script);
Invocable invocable = (Invocable) engine;
SimpleFile simpleFile = invocable.getInterface(SimpleFile.class);
simpleFile.create("simplefile.txt");
List list = new ArrayList();
list.add("A bird in the hand is worth two in the bush.");
list.add("Birds of a feather flock together.");
list.add("Every bird loves to hear himself sing.");
simpleFile.write(list);
simpleFile.close();
}

private void getInterfaceByClass(ScriptEngine engine) throws ScriptException {
String script =
"class SimpleFileImple\n" +
"import \'canna.SimpleFile\'\n" +
"def initialize(name)" +
"@name = name;" +
"@tmpfile = File.new(name, \"w\");" +
"@tmpfile.chmod(0600)" +
"end\n" +
"def write(message)" +
"message.each { |m| @tmpfile.puts(m) }" +
"end\n" +
"def close()" +
"@tmpfile.close;" +
"puts \"The file, #{@name}, has #{File.size(@name)} bytes.\"" +
"end\n" +
"end\n" +
"SimpleFileImple.new($name)";

engine.put("name", "simplefile2.txt");
Object object = engine.eval(script);
Invocable invocable = (Invocable) engine;
SimpleFile simpleFile = invocable.getInterface(object, SimpleFile.class);
List list = new ArrayList();
list.add("When it is a question of money, everybody is of the same religion.");
list.add("Money is the wise man's religion.");
simpleFile.write(list);
simpleFile.close();
}

private void getInterfaceMultipleStuffs(ScriptEngine engine) throws ScriptException {
String script =
"class Flowers\n" +
"import \'canna.Remarkable\'\n" +
"import \'canna.Removable\'\n" +
"@@hash = {\'red\' => \'ruby\', \'white\' => \'pearl\'}\n" +
"def initialize(color, names)" +
"@color = color;" +
"@names = names;" +
"end\n" +
"def remark\n" +
"puts \"#{@names.join(\', \')}. Beautiful like a #{@@hash[@color]}!\"" +
"end\n" +
"def remove(index)" +
"print \"If I remove #{@names[index]}, \";" +
"@names.delete_at(index);" +
"print \"others will be #{@names.join(\', \')}.\n\"" +
"end\n" +
"end\n" +
"red = Flowers.new(\"red\", [\"cameliia\", \"hibiscus\", \"rose\", \"canna\"])\n" +
"white = Flowers.new(\"white\", [\"gardenia\", \"lily\", \"magnolia\"])\n" +
"return red, white";

Object objects = engine.eval(script);
Invocable invocable = (Invocable) engine;
if (objects instanceof List) {
for (Object object : (List)objects) {
Object flower = invocable.getInterface(object, Remarkable.class);
((Remarkable)flower).remark();
flower = invocable.getInterface(object, Removable.class);
((Removable)flower).remove(1);
}
}
}

public static void main(String[] args)
throws ScriptException, NoSuchMethodException {
new GetInterfacesExample();
}
}

In above code, the second and third script don't have require 'java' statement because the first script has loaded java extension onto JRuby runtime and is valid until the program exits.

If these code gets run successfully, they produce outputs below:
he file, simplefile.txt, has 119 bytes.
The file, simplefile2.txt, has 101 bytes.
cameliia, hibiscus, rose, canna. Beautiful like a ruby!
If I remove hibiscus, others will be cameliia, rose, canna.
gardenia, lily, magnolia. Beautiful like a pearl!
If I remove lily, others will be gardenia, magnolia.
In addition, two files will be created on file system and have the mode 0600:
-rw-------   1 yoko  staff   119  4  2 14:06 simplefile.txt
-rw------- 1 yoko staff 101 4 2 14:06 simplefile2.txt