java调用ruby

由于spring只能调用jruby 0.9 - 1.0版本,为了调用更高版本的jruby 引擎,需要通过RS223接口来实现,以下是工作的一些总结希望对大家有帮助。


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());
	}
}

猜你喜欢

转载自fox1984.iteye.com/blog/1146453