sábado, 30 de janeiro de 2010

Invocação de funções e métodos do Python no Java (JSR-223)

Funções e métodos definidos no python podem ser invocados através da interface javax.script.Invocable. No Jython, essa interface é implementada também na mesma classe que implementa as interfaces javax.script.ScriptEngine e javax.script.Compilable. Portanto, é só chamar a fábrica de ScriptEngine para o python e obtendo uma instância de javax.script.ScriptEngine, fazer uma coerção para javax.script.Invocable. Abaixo temos dois exemplos para invocação de função definida no código fonte python no Java.

Observação: Se a função / método invocado não existirem no código python executado, será lançada um exceção java.lang.NoSuchMethodException indicando que não existe a função / método invocado.


Primeiro exemplo - Invocando função python que foi executado pelo método "eval" de javax.script.ScriptEngine
--------------------------------------------------------------------------------
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class PythonInvocableTest {

/**
* @param args
* @throws
*/
public static void main(String[] args) {
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine scriptEngine = scriptEngineManager
.getEngineByName("python");

if (scriptEngine != null) {

try {
scriptEngine
.eval("def imprimeTest(str): \n return str + u' Método invocado!' ");
} catch (ScriptException e) {
e.printStackTrace();
}

if (scriptEngine instanceof Invocable) {
Invocable invocable = (Invocable) scriptEngine;

Object object = null;

try {
object = invocable.invokeFunction("imprimeTest",
"oi jython!!");

} catch (ScriptException e1) {
e1.printStackTrace();

} catch (NoSuchMethodException e1) {
e1.printStackTrace();
}

if (object instanceof String) {
String str = (String) object;
System.out.println("Retorno do método: " + str);
}
}
}

System.out.println("Terminado com sucesso!!");
}
}

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


Segundo exemplo - Invocando função python que foi executado pelo método "eval" de javax.script.Compilable
--------------------------------------------------------------------------------
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class PythonInvocableTest2 {

/**
* @param args
*/
public static void main(String[] args) {
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine scriptEngine = scriptEngineManager
.getEngineByName("python");

if (scriptEngine != null) {

if (scriptEngine instanceof Compilable) {
Compilable compilable = (Compilable) scriptEngine;

CompiledScript compiledScript = null;

try {
compiledScript = compilable
.compile("def imprimeTest(str): \n return str + u' Método invocado!'");

} catch (ScriptException e) {
e.printStackTrace();
}

if (compiledScript != null) {

try {
compiledScript.eval();

} catch (ScriptException e) {
e.printStackTrace();
}
}
}

if (scriptEngine instanceof Invocable) {
Invocable invocable = (Invocable) scriptEngine;

Object object = null;

try {
object = invocable.invokeFunction("imprimeTest",
"oi jython!!");

} catch (ScriptException e1) {
e1.printStackTrace();

} catch (NoSuchMethodException e1) {
e1.printStackTrace();
}

if (object instanceof String) {
String str = (String) object;
System.out.println("Retorno do método: " + str);
}
}
}

System.out.println("Terminado com sucesso!!");
}
}

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


Terceiro exemplo - Invocando método da classe "A" definido no código python usando um objeto python.
--------------------------------------------------------------------------------
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class PythonInvocableTest3 {

/**
* @param args
*/
public static void main(String[] args) {
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine scriptEngine = scriptEngineManager
.getEngineByName("python");

if (scriptEngine != null) {

try {
scriptEngine
.eval("class A:\n def imprimeTest(self, str): \n return str + u' Método invocado!' + unicode(self.__class__()) \na = A()");
} catch (ScriptException e) {
e.printStackTrace();
}

if (scriptEngine instanceof Invocable) {
Invocable invocable = (Invocable) scriptEngine;

Object objectPython = scriptEngine.get("a");

Object object = null;

try {
object = invocable.invokeMethod(objectPython,
"imprimeTest", "oi jython!!");

} catch (ScriptException e1) {
e1.printStackTrace();

} catch (NoSuchMethodException e1) {
e1.printStackTrace();
}

if (object instanceof String) {
String str = (String) object;
System.out.println("Retorno do método: " + str);
}
}
}

System.out.println("Terminado com sucesso!!");
}
}

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

Executando código compilado Python no Java (JSR-223)

A biblioteca Jython implementa as especificações da API Java Scripting (JSR-223) e por isso, permite compilar código python para execução futura. Para isso, a implementação da interface javax.script.ScriptEngine fornecida pela Jython também implementa a interface javax.script.Compilable que fornece dois métodos para compilar o código fonte python que são:

public CompiledScript compile(String script) throws ScriptException;
public CompiledScript compile(Reader script) throws ScriptException;

Esses dois métodos permite compilar um código fonte em forma de java.lang.String ou java.io.Reader e com isso, retorna-se um objeto da classe abstrata javax.script.CompiledScript que permite fazer as chamadas aos métodos para executar o código compilado fonte como os seguintes métodos:

public Object eval() throws ScriptException
public Object eval(Bindings bindings) throws ScriptException
public abstract Object eval(ScriptContext context) throws ScriptException

Abaixo temos um código exemplo de como funciona a compilação de código fonte Python no Java.

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

import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class PythonCompileTest {

/**
* @param args
*/
public static void main(String[] args) {
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine scriptEngine = scriptEngineManager
.getEngineByName("python");

if (scriptEngine != null) {

if (scriptEngine instanceof Compilable) {
Compilable compilable = (Compilable) scriptEngine;

CompiledScript compiledScript = null;

try {
compiledScript = compilable
.compile("a = [] \nprint 'oi jython!!!'");

} catch (ScriptException e) {
e.printStackTrace();
}

if (compiledScript != null) {

try {
compiledScript.eval();

} catch (ScriptException e) {
e.printStackTrace();
}
}
}
}

System.out.println("Terminado com sucesso!!");
}
}

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

sábado, 23 de janeiro de 2010

Acessando variáveis do Java no Python

Podemos "enviar" os objetos do Java para o Python e através desse, podemos usar objetos Java como se fossem objetos do Python. Para isso, basicamente usamos o método "put" da interface javax.script.ScriptEngine. Nesse método, passamos o primeiro parâmetro o nome (java.lang.String) e o segundo parâmetro, passamos um objeto (java.lang.Object). Esse nome (primeiro parâmetro) será usado no python para acessar o objeto passado no segundo parâmetro.

Execute o exemplo abaixo:

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

import java.util.ArrayList;
import java.util.HashMap;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

/**
*
*/
public class JavaToPython {

/**
* @param args Argumentos.
*/
public static void main(String[] args) {
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("python");

if(scriptEngine != null) {
Object object[] = new Integer[3];
object[0] = new Integer(3);
object[1] = new Integer(4);
object[2] = new Integer(5);


scriptEngine.put("a", new Integer(3));
scriptEngine.put("b", new Double(3.45));
scriptEngine.put("c", new String("hello jython"));
scriptEngine.put("d", object);
scriptEngine.put("e", new ArrayList());
scriptEngine.put("f", new HashMap());

try {

scriptEngine.eval("print type(a), a");
scriptEngine.eval("print type(b), b");
scriptEngine.eval("print type(c), c");
scriptEngine.eval("print type(d), tuple(d)");
scriptEngine.eval("print type(e), list(e)");
scriptEngine.eval("print type(f), dict(f)");

} catch (ScriptException e) {
e.printStackTrace();
}
}
}
}

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

O objeto de nome "a" passado no método "put" é do tipo java.lang.Integer que no python equivale ao tipo "int".

O objeto de nome "b" passado no método "put" é do tipo java.lang.Double que no python equivale ao tipo "float".

O objeto de nome "c" passado no método "put" é do tipo java.lang.String que no python equivale ao tipo "unicode".

O objeto de nome "d" passado no método "put" é um array do tipo java.lang.Integer que no python equivale ao tipo "array.array". Mas no exemplo, podemos transformar o tipo "array.array" no tipo "tuple" que é um tipo mais usual no python.

O objeto de nome "e" passado no método "put" é do tipo java.util.ArrayList que no python equivale ao tipo "java.util.ArrayList". Mas no exemplo, podemos transformar o tipo "java.util.ArrayList" no tipo "list" que é um tipo mais usual no python.

O objeto de nome "f" passado no método "put" é do tipo java.util.HashMap que no python equivale ao tipo "java.util.HashMap". Mas no exemplo, podemos transformar o tipo "java.util.HashMap" no tipo "dict" que é um tipo mais usual no python.

Acessando variáveis do Python no Java

Para acessar variáveis do Python no Java basicamente usamos o método "get" da interface javax.script.ScriptEngine. Esse método, retorna um java.lang.Object cujo tipo está relacionado ao tipo usado no Python. Veja o exemplo abaixo:

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

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

/**
*
*/
public class PythonToJava {

/**
* @param args Array de argumentos.
*/
public static void main(String[] args) {
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("python");

if(scriptEngine != null) {

try {
scriptEngine.eval("a=3 \nb=3.45 \nc=u'hello jython' \nd=3, 4, 5 \ne=[] \nf={}");

} catch (ScriptException e) {
e.printStackTrace();
}

Object object[] = new Object[6];

object[0] = scriptEngine.get("a");
object[1] = scriptEngine.get("b");
object[2] = scriptEngine.get("c");
object[3] = scriptEngine.get("d");
object[4] = scriptEngine.get("e");
object[5] = scriptEngine.get("f");

for (int i = 0; i < object.length; i++) {
System.out.println("object[" + i + "]: " + object[i].getClass());
}
}

System.out.println("Terminado com sucesso!!");
}
}

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

Se o Jython, Java e Python estiverem instalados corretamente, veremos a seguinte saída no console:


-----------------------------------------------------------------------------------
object[0]: class java.lang.Integer
object[1]: class java.lang.Double
object[2]: class java.lang.String
object[3]: class org.python.core.PyTuple
object[4]: class org.python.core.PyList
object[5]: class org.python.core.PyDictionary
Terminado com sucesso!!
-----------------------------------------------------------------------------------

O objeto "object[0]" retornado equivale ao tipo java.lang.Integer que é uma classe empacotadora de inteiros.

O objeto "object[1]" retornado equivale ao tipo java.lang.Double que é uma classe empacotadora de número de ponto flutuante de precisão dupla.

O objeto "object[2]" retornado equivale ao tipo java.lang.String que é uma cadeia de caracteres unicode.

O objeto "object[3]" retornado equivale ao tipo org.python.core.PyTuple que é uma classe que implementa a interface java.util.List. Mas, lembrando que esse tipo equivale ao tipo "tuple" no Python que é uma lista somente no modo leitura. Portanto, ao usar os métodos "add", "addAll", "clear", "remove", "removeAll", "retainAll" e "set" da interface java.util.List sobre a implementação org.python.core.PyTuple, retorna uma exceção java.lang.UnsupportedOperationException indicando que a operação não é suportada, pois tenta alterar a lista (org.python.core.PyTuple). Portanto, só deve ser usado os métodos de "leitura" da classe java.util.List.

O objeto "object[4]" retornado equivale ao tipo org.python.core.PyList que é uma classe que implementa a interface java.util.List.

O objeto "object[5]" retornado equivale ao tipo org.python.core.PyDictionary que é uma classe que implementa a interface java.util.concurrent.ConcurrentMap que por sua vez implementa a interface java.util.Map.


Veja na figura abaixo o mapeamento dos objetos Python para o Java.

Usando o Jython com a Java Scripting API (JSR-223)

O Jython permite usar o Python no Java e vice-versa. Permite rodar script em python usando a máquina virtual do Java.


INSTALAÇÃO


Primeiramente, precisa estar instalado o JDK 6 e o Python.
Para isso, acesse:

http://www.python.org/
E baixe a última versão do python (2.6.4 a última versão desde na edição desse artigo) e depois faça a instalação.

http://java.sun.com/javase/downloads/index.jsp

Baixe a última versão da versão 6 do Java (1.6.18 a última versão na edição desse artigo) e depois faça a instalação.


Tendo os ambientes de desenvolvimento Java e Python instalados, agora prosseguimos com a instalação de Jython. Para isso, acesse o site: http://www.jython.org/ e baixe a última versão (2.5.1 na edição desse artigo).

Depois feita a instalação, precisamos referenciar Jython no PATH, lembrando que o PATH para a execução de programas utilitários do Jython estão dentro da pasta bin do diretório raiz de instalação do Jython. Assim, se o Jython foi instalado no diretório /usr/local/jython2.5, então o caminho a ser usado no PATH do sistema operacional é /usr/local/jython2.5/bin.

Da mesma maneira, precisamos referenciar o arquivo "jython.jar" que está no diretório raiz da instalação do Jython no CLASSPATH. Por exemplo, se o Jython foi instalado no diretório /usr/local/jython2.5.1, o caminho a ser usado no CLASSPATH é /usr/local/jython2.5.1/jython.jar.


EXEMPLO

Depois de instalado o JDK 6, Python e Jython, execute o exemplo abaixo:

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

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

/**
*
*/
public class PythonTest {

/**
* @param args
*/
public static void main(String[] args) {
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("python");

if(scriptEngine != null) {

try {
scriptEngine.eval("a = [] \nprint 'oi jython!!!' ");

} catch (ScriptException e) {
e.printStackTrace();
}

}

System.out.println("Terminado com sucesso!!");
}
}

--------------------------------------------------------------------------------------
Se tudo estiver corretamente instalado, o resultado que será mostrado no console deverar ser:

oi jython!!!
Terminado com sucesso!!

Introdução a Java Scripting API (JSR-223)

INTRODUÇÃO

A Interface de programação de aplicações para uso de scripting está inclusa na versão 6 da linguagem Java e permite o uso de linguagens dinâmicas dentro do código Java. Sem essa API, teríamos que usar a interface nativa do Java (JNI) em código C/C++ e assim poder chamar os interpretadores das linguagens de scripting para poder rodar os códigos dessas linguagens dinâmicas e assim, enviar as variáveis a máquina virtual do Java.
A Java Scripting API facilita a integração do Java com outras linguagens dinâmicas, como python, ruby, etc. Nesse tutorial, daremos uma introdução do uso dessa API.


ARQUITETURA DA JSR-223

A API de scripting está contida no pacote javax.script e cujas classes e interfaces do pacotes são:
- ScriptEngineManager
Gerencia as fábricas de interpretadores para as linguagens dinâmicas.

- ScriptEngineFactory (Interface)
Fabrica (segundo padrão Factory) para uma linguagem de scripting específica.

- ScriptEngine (Interface)
Interpretador para uma linguagem de scripting específica.

- Bindings (Interface)
Mapeamento de vínculos entre nomes e objetos Java. Esse mapeamento permite que as linguagens de scripting consigam acessar objetos criados em Java.

- ScriptContext (Interface)
Contexto de execução de uma linguagem de scripting específica. Fornece recursos para acessar o leitor de entrada, escritor de saída e de erro.

- Invocable (Interface)
Permite a execução de funções de scripts que já foram avaliados.

EXEMPLO

Executando esse exemplo abaixo permite listar os motores de script instalados.
Para instalar um motor de script, basta colocar os pacotes ".jar" fornecidos pelas linguagens de script no CLASSPATH. No JDK 6 já vem o suporte para JavaScript através do motor Rhino.

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

import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;


public class EnginesTest {

/**
* @param args
*/
public static void main(String[] args) {
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();

for (ScriptEngineFactory scriptEngineFactory : scriptEngineManager.getEngineFactories()) {
System.out.println("EngineName: " + scriptEngineFactory.getEngineName());
System.out.println("EngineVersion: " + scriptEngineFactory.getEngineVersion());
System.out.println("LanguageName: " + scriptEngineFactory.getLanguageName());
System.out.println("LanguageVersion: " + scriptEngineFactory.getLanguageVersion());

// Extensões
StringBuffer strBuffer1 = new StringBuffer();

for (String string : scriptEngineFactory.getExtensions()) {
strBuffer1.append(string + " \n");

}

System.out.println("Extensions: \n" + strBuffer1.toString());

// Tipos de MIME'S
StringBuffer strBuffer2 = new StringBuffer();

for (String string : scriptEngineFactory.getMimeTypes()) {
strBuffer2.append(string + " \n");
}

System.out.println("Mime Types: \n" + strBuffer2.toString());

// Nomes
StringBuffer strBuffer3 = new StringBuffer();

for (String string : scriptEngineFactory.getNames()) {
strBuffer3.append(string + " \n");
}

System.out.println("Names: \n" + strBuffer3.toString());

// ScriptEngine
ScriptEngine scriptEngine = scriptEngineFactory.getScriptEngine();

System.out.println("-----------------------------");
}
}
}

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

REFERÊNCIAS


http://jcp.org/en/jsr/summary?id=223
http://java.sun.com/docs/books/jni/

sábado, 2 de janeiro de 2010

UM ESPECIALISTA GENERALISTA

Atualmente, se ouve falar muito na atuação de profissionais especialistas em diversas áreas. Por exemplo, ao invés de se formar um profissional em engenharia elétrica, se forma um especialista em telecomunicações para atuar num seguimento bem especifico do mercado. Mas, no desenvolvimento de seu trabalho, o especialista em telecomunicações precise atuar na área de engenharia de materiais, pois existe a necessidade de procurar outros materiais cujas características sejam mais favoraveis para a aplicação em telecomunicações. Como ficaria um profissional que só conhece telecomunicações ? E por outro lado, se existe um profissional generalista que conhece tudo em uma determinada área, mas sem muita profundidade, como por exemplo, o engenheiro elétrico, que conhece um pouco de cada sub-área da engenharia elétrica, como telecomunicações, eletrônica, eletrotécnica, microeletrônica, computação e outras. Mas se precisa construir um circuito eletrônico para processamento de sinais cujas ondas nenhum outro circuito processa atualmente, como construirá esse dispositivo, sendo que o mesmo depende de conhecimentos especificos sobre o seu projeto, escolha de componentes, caracterização e outros ?

Por isso, concluímos que não pode existir um profissional 100% especialista ou generalista. Sempre um generalista precisa conhecer alguma sub-área de maneira mais aprofundada, ou um especialista precisa conhecer as outras áreas relacionadas a sua. No final, temos sempre um profissional especialista generalista ou generalista especialista!


José P. O. Jr