Ramon Pereira Lopes

Sun Campus Ambassador at UFBA


« Previous day (Jul 13, 2008) | Main | Next day (Jul 14, 2008) »
Segunda-feira Jul 14, 2008

Java invocando Ruby - JSR 223

A JSR 223 define um padrão para uso de linguagens de scripts com a plataforma Java, isto é, de uma aplicação Java podemos utilizar os recursos de diversas linguagens de Script, tais como Python/Ruby/Tcl/JavaScript/etc, invocando funções, definindo classes e utilizando-as no código Java, resumindo, podemos extrair o melhor da linguagem de script escolhida e unir ao poder da plataforma Java.

A fim de utilizar a API de Scripting, faz-se necessário obter o engine apropriado, por padrão, o Java 6 tem a implementação de um engine para JavaScript denominado Mozilla Rhino. No nosso caso, iremos utilizar Ruby como linguagem de script, portanto devemos adicionar o engine ao conjunto de bibliotecas da nossa aplicação, como também o jruby. Não se preocupem, pois deixarei os arquivos disponíveis para download ao final do post.

Como citado anteriormente, o primeiro passo é baixar o engine da sua linguagem de script e demais .jar e adicioná-los ao conjunto de bibliotecas da sua aplicação. Para aqueles que não estão familiarizados com a sintaxe de Ruby, aconselho a dar uma rápida estudada de 15 minutinhos, acredite Ruby é muito fácil e intuitivo.

Nossa aplicação contém um arquivo denominado script.rb, no qual teremos a definição de funções e de uma classe que, de ambos, faremos uso na aplicação Java. Acredito que a melhor forma de aprender é na prática e explicando passo-a-passo. Vamos agora dissecar a nosso método principal da aplicação Java.

O primeiro passo para se utilizar Scripting é obter uma referência ao ScriptEngineManager, cuja função é 'fabricar' os engines, além de identificar quais estão disponíveis, para este recurso recomendo dar uma olhada no método getEngineFactories().
ScriptEngineManager manager = new ScriptEngineManager();

Uma vez com uma referência ao Manager, nós podemos obter a referência ao ScriptEngine, que será responsável pela análise de blocos, invocar funções e métodos. Reparem que ao obter tal instância, devemos passar o nome do engine requerido, para uma lista completa é interessante conferir o site oficial do projeto Scripting, no qual podemos baixar os engines.
ScriptEngine engine = manager.getEngineByName("jruby");

Com a referência ao engine, podemos invocar método Ruby simplesmente passando como argumento o nosso código. No caso exemplo abaixo, declaro uma variável e invoco o método puts do Ruby para exibir na saída padrão.
engine.eval("x = 10; puts \"Hello World! #{x}\"");

Até o momento só vimos um único exemplo em que passávamos o bloco de código em Ruby para execução, então podemos nos perguntar se será sempre dessa maneira. A resposta, obviamente é não, no seguinte trecho fazendo uma análise por inteiro de um arquivo Ruby.
engine.eval(new BufferedReader(new FileReader("./src/scripting/script.rb")));

Para de fato invocar as funções e métodos que já foram 'reconhecidas' pelo engine devemos utilizar uma interface denominada Invocable. Basicamente, tal interface nos permite invocar Funções e Método. A obtenção da referência é feita simplesmente com um simples Cast.
Invocable invoke = (Invocable) engine;

A fim de invocar uma funçao definida no nosso arquivo Ruby, utilizamos o método invokeFunction, cujo primeiro parâmetro é nome da função, enquanto o segundo é um Varargs de Object (VarArgs tema de certificação SCJP!!)
invoke.invokeFunction("soma", 1, 2);

A seguinte declaração merece uma atenção especial:
long idade = (Long) invoke.invokeMethod(p1, "idade");

Utilizamos o método invokeMethod que retorna uma referência a object, reparem que fizemos um cast para Long, por quê? A explicação vem da seguinte tabela de conversões de tipos java (à direita) para Ruby (à esquerda):
Boolean boolean, java.lang.Boolean
Fixnum byte, java.lang.Byte, short, java.lang.Short, int, java.lang.Integer
Float float, java.lang.Float, double, java.lang.Double
String char, java.lang.String
Array java.util.List
Hash java.util.Map

Alguns trechos que não foram explanados ficam como exercício.

Links:
JRuby.jar - Não pude anexar por conta do tamanho do arquivo, mas vocês podem encontrá-lo na página oficial do projeto ou na pasta do Netbeans/ruby2
JRuby-engine
Projeto Exemplo


Today's Page Hits: 0