由于spring只能调用jruby 0.9 - 1.0版本,为了调用更高版本的jruby 引擎,需要通过RS223接口来实现,以下是工作的一些总结希望对大家有帮助。
1、对RS232的一些封装,方便调用
2、工具类,用于查找脚本文件
3、测试代码
接口定义
接口实现
测试代码
1、对RS232的一些封装,方便调用
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import org.apache.commons.lang.StringUtils;
public class JrubyUtil {
private LoadedScriptFile loaded = new LoadedScriptFile(
SuperScriptEngineFactory.JRUBY_ENGINE_NAME);
public Object getInstance(Class<?> impl) {
return loaded.getInstance(
ScriptFileHelper.getJrubyScriptFile(impl, SuperScriptEngineFactory.JRUBY_ENGINE_NAME), impl);
}
public Object getInstance(Class<?> impl, String fun) {
return loaded.getInstance(
ScriptFileHelper.getJrubyScriptFile(impl, SuperScriptEngineFactory.JRUBY_ENGINE_NAME), impl, fun);
}
}
/**
* 封装rs-223的实现,适用于各种脚本语言
*/
class SuperScriptEngine {
protected ScriptEngine engine;
/**
*
* @param name 所需要使用引擎名称
*/
public SuperScriptEngine(String name) {
ScriptEngineManager manager = new ScriptEngineManager();
engine = manager.getEngineByName(name);
System.out.println(engine.getFactory().getEngineName());
}
/**
*
* @param in 脚本文件的文件流
* @return 编译完成的脚本对象
*/
public CompiledScript compiled(InputStream in) {
CompiledScript compileScript = null;
try {
if (engine instanceof Compilable) {
Compilable compile = (Compilable) engine;
compileScript = compile.compile(
new InputStreamReader(in));
}
} catch (ScriptException e) {
e.printStackTrace();
}
return compileScript;
}
/**
* @param impl 脚本所需实现的接口
* @param in 脚本文件的文件流
* @param fun 脚本中负责初始化的函数名
* @return 返回接口实现的对象
* <p>fun函数最后必须返回实现的对象,如果为空则脚本结束的返回值必须返回对象</p>
*/
public Object getInterface(Class<?> impl, InputStream in, String fun) {
Object interfaceInstance = null;
Object result = null;
try {
if (engine instanceof Invocable) {
result = engine.eval(
new InputStreamReader(in));
Invocable invocable = (Invocable) engine;
if (StringUtils.isBlank(fun)) {
interfaceInstance = invocable.getInterface(result, impl);
} else {
result = invocable.invokeFunction(fun);
interfaceInstance = invocable.getInterface(result, impl);
}
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ScriptException e) {
e.printStackTrace();
}
return interfaceInstance;
}
/**
*
* @param impl 脚本所需实现的接口
* @param in 脚本文件的文件流
* @return 返回接口实现的对象
* <p>脚本中最后必须返回实现的对象</p>
*/
public Object getInterface(Class<?> impl, InputStream in) {
return getInterface(impl, in, "");
}
/**
* @param impl 脚本所需实现的接口
* @param compileScript 编译后的脚本对象
* @param fun 脚本中负责初始化的函数名
* @return 返回接口实现的对象
* <p>fun函数最后必须返回实现的对象,如果为空则脚本结束的返回值必须返回对象</p>
*/
public Object getInterface(Class<?> impl, CompiledScript compileScript, String fun) {
Object interfaceInstance = null;
Object result = null;
try {
ScriptEngine engine = compileScript.getEngine();
if (engine instanceof Invocable) {
result = compileScript.eval();
Invocable invocable = (Invocable) engine;
if(StringUtils.isBlank(fun)) {
interfaceInstance = invocable.getInterface(result, impl);
} else {
result = invocable.invokeFunction(fun);
interfaceInstance = invocable.getInterface(result, impl);
}
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ScriptException e) {
e.printStackTrace();
}
return interfaceInstance;
}
/**
* @param 脚本所需实现的接口
* @param 编译后的脚本对象
* @return 返回接口实现的对象
* <p>脚本中最后必须返回实现的对象</p>
*/
public Object getInterface(Class<?> impl, CompiledScript compileScript) {
return getInterface(impl, compileScript, null);
}
/**
* @param str 文本形式的脚本代码
* @return 执行后脚本的返回值
*/
public Object eval(String str) {
Object result = null;
try {
result = engine.eval(str);
} catch (ScriptException e) {
e.printStackTrace();
}
return result;
}
/**
*
* @param str 脚本代码
* @param context 脚本引擎上下文
* @return 执行后脚本的返回值
*/
public Object eval(String str, ScriptContext context) {
Object result = null;
try {
result = engine.eval(str, context);
} catch (ScriptException e) {
e.printStackTrace();
}
return result;
}
/**
*
* @param in 脚本文件流
* @return 执行后脚本的返回值
*/
public Object eval(InputStream in) {
Object result = null;
try {
result = engine.eval(new InputStreamReader(in));
} catch (ScriptException e) {
e.printStackTrace();
}
return result;
}
/**
*
* @param in 脚本文件流
* @param context 脚本引擎上下文
* @return 执行后脚本的返回值
*/
public Object eval(InputStream in, ScriptContext context) {
Object result = null;
try {
result = engine.eval(new InputStreamReader(in), context);
} catch (ScriptException e) {
e.printStackTrace();
}
return result;
}
}
/**
* 封装rs-223的实现,适用于各种脚本语言,jruby引擎的实现
*/
class JrubySuperScriptEngine extends SuperScriptEngine {
private static JrubySuperScriptEngine jrEngine;
synchronized public static JrubySuperScriptEngine getInstance() {
if (jrEngine == null) {
System.setProperty("org.jruby.embed.compilemode", "jit");
jrEngine = new JrubySuperScriptEngine("jruby");
}
return jrEngine;
}
public JrubySuperScriptEngine(String name) {
super(name);
}
}
/**
* 脚本引擎工厂类,负责实例化脚本引擎对象
*/
class SuperScriptEngineFactory {
public final static String JRUBY_ENGINE_NAME = "JRUBY";
synchronized public static SuperScriptEngine getInstance(String engineName) {
SuperScriptEngine instance = null;
if (engineName.toUpperCase().equals(JRUBY_ENGINE_NAME)) {
instance = JrubySuperScriptEngine.getInstance();
}
return instance;
}
}
/**
* 脚本文件封装
*/
class ScriptFile {
/** 脚本文件名称 */
protected String name;
/** 脚本的hash值 */
protected int hash;
/** 脚本的路径 */
protected String path;
/** 脚本的文件流 */
protected InputStream in;
public ScriptFile(File file) throws FileNotFoundException {
in = new FileInputStream(file);
name = file.getName();
path = file.getPath();
hash = file.hashCode();
}
public String getName() {
return name;
}
public String getPath() {
return path;
}
public int getHash() {
return hash;
}
public InputStream getInputStream() {
return in;
}
}
/**
* 脚本文件管理
*/
class LoadedScriptFile {
public final static String DEFAULT_GET_INSTANCE = "getInstance";
protected SuperScriptEngine engine;
protected Class<?> impl;
public LoadedScriptFile(String engineName) {
this.engine = SuperScriptEngineFactory.getInstance(engineName);
}
public SuperScriptEngine getEngine() {
return engine;
}
public Object getInstance(ScriptFile scriptFile, Class<?> impl, String fun) {
Object instance = null;
instance = engine.getInterface(impl,
scriptFile.getInputStream(), fun);
return instance;
}
public Object getInstance(ScriptFile scriptFile, Class<?> impl) {
return getInstance(scriptFile, impl, "");
}
}
2、工具类,用于查找脚本文件
import java.io.File;
import java.io.FileNotFoundException;
import java.net.URISyntaxException;
import java.net.URL;
import junit.framework.Assert;
/**
*
* 读取脚本文件,适合各种不同后缀脚本
*/
public class ScriptFileHelper {
private final static String SCRIPT_HOME = "SCRIPT_HOME";
private final static String SEPARATOR = System.getProperty("file.separator");
private final static String JRUBY_SUFFIX = ".rb";
/**
* 根据文件名读入资源文件
* 查找范围及优先级:
* 1. classes目录下的fileName;
* 2. 环境变量SCRIPT_HOME下的filaName;
* 3. 当前工作空间下resources目录下的filaName;
*/
public static ScriptFile getScriptFileOnFileName(String fileName) {
ScriptFile scriptFile = null;
try {
URL resource = ScriptFileHelper.class.getResource("/" + fileName);
if (resource != null) {
scriptFile = new ScriptFile(new File(resource.toURI()));
}
if (scriptFile == null) {
String[] paths = {
System.getProperty(SCRIPT_HOME) + fileName,
System.getProperty("user.dir") + SEPARATOR + "scriptfiles" + SEPARATOR + fileName};
for (String path : paths) {
System.out.println(path);
if ((new File(path)).isFile()) {
scriptFile = new ScriptFile(new File(path));
break;
}
}
}
} catch (FileNotFoundException e) {
System.out.println(e.getStackTrace());
} catch (URISyntaxException e) {
System.out.println(e.getStackTrace());
}
Assert.assertNotNull(scriptFile);
return scriptFile;
}
/**
* 根据类名读取脚本文件
* 查找范围及优先级:
* 1. impl所在目录下同名的脚本;
* 2. classes目录下的fileName;
*/
public static ScriptFile getScriptFileOnImpl(Class<?> impl, String suffix) {
ScriptFile scriptFile = null;
try {
// 读取当前包下同名的文件
String implName = impl.getSimpleName() + suffix;
URL resource = impl.getResource(implName);
if (resource == null) {
// 读取classes下同名的文件
resource = impl.getResource("/" + implName);
}
if (resource != null) {
scriptFile = new ScriptFile(new File(resource.toURI()));
}
} catch (URISyntaxException e) {
System.out.println(e.getStackTrace());
} catch (FileNotFoundException e) {
System.out.println(e.getStackTrace());
}
Assert.assertNotNull(scriptFile);
return scriptFile;
}
/**
* 1. 根据全路径加载脚本文件
*/
public static ScriptFile getScriptFileOnFullPath(String fullPath) {
ScriptFile scriptFile = null;
try {
if ((new File(fullPath)).isFile()) {
scriptFile = new ScriptFile(new File(fullPath));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Assert.assertNotNull(scriptFile);
return scriptFile;
}
/**
* 根据类名,脚本引擎名,读取脚本文件
* 查找范围及优先级:
*/
public static ScriptFile getJrubyScriptFile(Class<?> impl, String engineName) {
ScriptFile reslut = null;
if (engineName.toUpperCase().equals(SuperScriptEngineFactory.JRUBY_ENGINE_NAME)) {
reslut = getScriptFileOnImpl(impl, JRUBY_SUFFIX);
}
return reslut;
}
}
3、测试代码
接口定义
public interface Message {
public String sayHello();
}
接口实现
require 'java'
class RubyMessage
include_class 'test.wireless.auto.ruby.Message'
def sayHello
return 'hello java'
end
end
RubyMessage.new
测试代码
public class MessageTest {
@Test
public void test_JrubyUtilTest() {
JrubyUtil jruby = new JrubyUtil();
Object result = jruby.getInstance(Message.class);
System.out.println(((Message)result).sayHello());
}
}