Rhino: Executando código de javascript na plataforma java ! 27/03/2009
Posted by fredericobenevides in Rhino.3 comments
Para quem não sabe, a jvm permite executar vários tipos de linguagens além da própria linguagem Java.
Alguns exemplos de outras linguagens que rodam na jvm:
- JRuby (implementação em java da linguagem Ruby)
- Groovy
- Scala
- JavaFX
- Rhino (implementação Java do Javascript)
- CajuScript (projeto brasileiro http://code.google.com/p/cajuscript/)
Alguém poderia perguntar o por que de usar outra linguagem na jvm além da própria linguagem java. Bem, um dos itens que eu diria, existem linguagens que oferecem mais agilidade para resolver algum problema do que a própria linguagem java. E pra quem mexe a muito tempo em java, e que conhece outras linguagens, percebe que a linguagem java não é tão bonita assim e nem tão ágil. Pra ser sincero, acredito mais no futuro da plataforma Java do que na linguagem, mas isso não vem ao caso nesse tópico.
Existem linguagens dinâmicas que oferecem mais agilidade para desenvolver e resolver vários problemas, uma delas, o Ruby. Por exemplo, para somar um array no Ruby 1.9 eu poderia simplesmente usar isso => %w[1 2 3 4 5].inject(:+) Claro que pra quem não conhece a linguagem acha estranho, mas o detalhe é que em java teria mais algumas linhas. Então se achar que alguma linguagem te oferece mais produtividade em determinada parte do código, por que não usá-la?
Agora, o melhor de tudo é juntar a interoperabilidade que a jvm ofecere, e ainda ter linguagens mais práticas/ágéis podendo ser executadas em qualquer ambiente. Ótimo, não é mesmo!?
Vamos ao assunto que interessa. Rhino! O que tem de especial executar javascript na plataforma Java? Já aconteceu de alguns projetos você ter que repetir códigos que são feito em validações de javascript usar no seu programa? Saco, não é mesmo!? Cadê a reutilização de código? Cadê a produtividade? (apesar que alguns casos vai no ctrl+c ctrl+v e mais adaptação do código).
Para resolver alguns destes problemas a gente pode utilizar o Rhino, e com isso termos reutilização de códigos. Desenvolvemos o código em javascript e pronto, fazemos o java chamar determinada função de javascript e voilà, seu código java já está funcionando sem ter necessidade que implementar tudo novamente. Detalhe por padrão no java 6 já vem o Rhino, facilitando a praticidade de não precisar baixar o rhino e colocar no classpath do seu projeto.
O processo para rodar o Rhino dentro do java.
- Criar a fábrica ScriptEngineManager para construir ScriptEngine
- Criar o objeto que vai manipular determinada linguagem
- Avaliar o conteúdo da linguagem e executá-la
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
engine.eval("println('JavaScript Executando')");
Simples não é mesmo?
Agora vamos utilizar um arquivo de javascript, nesse próximo exemplo usando uma função fatorial.
Conteúdo do javascript:
function fatorial(n) {
if (n == 1) return 1;
return n * fatorial(n-1);
}
n = 3
println("O fatorial de " + n + " é: " + fatorial(n));
Código
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
engine.eval(new FileReader("fatorial.js");
Se você reparou bem, quem está chamando a execucação da função está no próprio arquivo do javascript. “Mas não é isso que quero, quero passar o argumento pelo código java, tem jeito?”. Claro que tem, vamos ver:
Arquivo atualizado, sem a chamada para a função:
function fatorial(n) {
if (n == 1) return 1;
return n * fatorial(n-1);
}
Código:
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
engine.eval(new FileReader("fatorial2.js");
Invocable invocable = (Invocable) engine;
int fatorial = 3;
Double resultado = (Double) invocable
.invokeFunction("fatorial", fatorial );
System.out.println("O fatorial de " + fatorial +
" é: " + resultado.intValue());
Como podem ver, nesse código passei o meu engine para o tipo invocable. Especifiquei qual o nome da função, e passei o argumento para a função em que o resultado desta chamada me retorna um Object.
Que tal outro exemplo? Vamos fazer agora uma validação de e-mail. Olha, não estou entrando nada em detalhe de hibernate validator, de validação via ajax, mas sim no uso do Rhino dentro do Java, então não há de ter pensamentos: “eu poderia fazer isso usando hibernate validator”, “usando ajax”, etc. Lembre-se sempre disso, isso é para alguns casos que seu código de javascript é o mesmo do seu código java.
function validar_email(email) {
regex = /^[a-zA-Z0-9][a-zA-Z0-9\._-]+@([a-zA-Z0-9\._-]+\.)[a-zA-Z-0-9]{2}/;
if(regex.exec(email)) {
return true;
} else {
return false;
}
}
Código:
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
engine.eval(FileLoad.load("email.js"));
Invocable invocable = (Invocable) engine;
String email = "usuario@email.com.br";
Boolean resultado = (Boolean) invocable
.invokeFunction("validar_email", email);
System.out.println("O email é válido ? " + resultado);
email = "usuario";
resultado = (Boolean) invocable
.invokeFunction("validar_email", email);
System.out.println("O email é válido ? " + resultado);
Interessante não? Mas você sabia também que é possível utilizar as bibliotecas do java escrevendo com javascript? E que tal implementar um JFrame escrevendo javascript? Ah, e que tal não ter que preocupar em declarar o tipo de objeto, já que javascript é uma linguagem dinâmica? Pois é, o Rhino permite fazer tudo isso!
Vejamos um exemplo como seria criar uma janela:
Arquivo js:
importPackage(javax.swing); importPackage(java.awt); var frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(600, 400); frame.setVisible(true);
Como podem ver para importar usando o javascript preciso digitar, importPackage(nomeDoPacote) , o resto é normal como se fosse em java, mas claro, sem ter a necessidade de declarar o tipo do objeto, afinal em javascript não precisa.
Código
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
engine.eval(new FileReader("simples_jframe.js");
Para rodar, simplesmente carrega o arquivo, e pronto, ele mostrará o JFrame.
Achei até interessante isso de desenvolver java usando javascript, que eu fiz um estudo de implementar um JFrame usando Threads. Caso vocês tenham interesse, vocês podem baixar o projeto “blog_rhino” no seguinte endereço do github: git://github.com/fredericobenevides/blog_rhino.git. Dentro desse projeto também terá todos os exemplos citados aqui no blog.
Passos para quem não sabe baixar o projeto e importar para o eclipse:
- Digitar o seguinte comando no console: git clone git://github.com/fredericobenevides/blog_rhino.git
- cd blog_rhino
- mvn eclipse:eclipse (Fazendo o maven criar os arquivos necessários para importar para o eclipse)
- Abrir o eclipse e acessar File -> import -> General -> Existing Projects Into Workspace
- “Brincar com o projeto”
Espero que tenham curtido, e se caso um dia achar que possa reutilizar um código javascript… por que não usar Rhino?
Reinventar a Roda 09/03/2009
Posted by fredericobenevides in Desenvolvimento.3 comments
Desde que eu mudei para Brasília, trabalhei com vários tipos de aplicações. Algumas, ou quem sabe maioria destas aplicações, eu vi o que a maioria é acostumado de ver, funcional por fora, mas internamente, horrível de se trabalhar.
Algumas destas aplicações o que eu nunca consegui entender, é como o pessoal reinventa a roda! E como REINVENTAM! Se fossem boas, tudo bem, mas a maioria não é. Pra ser sincero, não lembro de um destes se teve UM que valeu a pena, mas não vou chegar a ser tão crítico.
Eu nunca gostei disso, pois atrapalham muito o desenvolvimento. Estas implementações geralmente não existem testes, e o pior, na solução existente poderia estar trabalhando no meu negócio e não nos problemas da estrutura de um framework.
Para se ter uma idéia, um dos frameworks mvc que trabalhei, nele encontrava mais outro mvc, o struts. O negócio era uma bomba, que futuramente eles implantaram o struts para algumas partes do sistema. Infelizmente, legado é legado e logo muito da bomba ainda continuava lá, tanto que ele chegou a ter um problema que após uma certa quantidade de usuários, permitia que alguns usuários acessavam com perfil de outros usuários. Imagina o problema disso…
Já vi também criarem sistemas para controle de bugs, sendo que, existem muitos sistemas bons e livres tais como trac e bugzilla. Agora se pudessem parar pra analisar o tempo e o dinheiro que gastou com analistas e desenvolvedores para implementar este software, sairia mais barato pagando licença do Jira. E uma pequena observação, sairia mais barato e teria um sistema bem melhor.
Outra, trabalho com uma aplicação que até inventaram a camada de persistência, e o pior, os que desenvolveram achavam que o design era ótimo. Até já teve uns bugs que por exemplo, se fosse buscar uma pessoa pelo id, o que retornava era apenas um o objeto pessoa com o seu atributo ID sem o restante das informações do usuário. Pois é, era mais fácil fazer new Pessoa(id)…
Nesse tempo, o que eu cheguei a perceber, ou pelo menos parece com o pensamento de certos tipos de desenvolvedores: “Eu sou um bom desenvolvedor e sei fazer a minha própria aplicação, não preciso de soluções existentes”. Claro que eu não sei o que passou na mente de cada um para reinventar a roda, mas será que já perguntaram para si mesmo: “O que a minha aplicação terá o que as outras não tem?”, ou quem sabe pensar: “Vale a pena o tempo que vou gastar para desenvolver do que estudar um outro framework?”.
Lembre-se, reinventar a roda nem sempre é o caminho para uma solução, e sim, apenas o começo de alguns problemas.
Testes… O salvador! 02/03/2009
Posted by fredericobenevides in Desenvolvimento.6 comments
Este primeiro post vou escrever sobre um assunto que até para muitos já estão cansados de saber, que é sobre o uso de testes no desenvolvimento de software. Neste post não vou explicar como fazer testes unitários na sua aplicação, vou falar um pouco das experiências que eu tive usando testes, mais especificamente com o JUnit.
Desde que eu comecei a “brincar” com testes fiquei meio viciado. O vício aconteceu quando eu comecei a ver que, a segurança que o teste me provê é inverso aos problemas que terei. Pois quanto de nós já deve ter tido problema de ter que arrumar algo que antes funcionava, perder tempo para concertar erros por causa de alguma outra manuntenção que quebrou o seu código. Perder horas, ou dias, por problemas que foram inseridos e não testado corretamente antes de subir para algum ambiente. Pois é, ninguém gosta disso, tanto desenvolvedor, ou até mesmos os responsáveis pela empresa em que trabalha, pois perda de tempo, é dinheiro jogado fora. Então, por mais que leve um tempo maior para implementar com mais segurança, é melhor ter um tempo maior de desenvolvimento, do que em um breve futuro seu código possa ser quebrado por causa de atualizações de outras pessoas, ou até mesmo as suas próprias atualizações.
Um exemplo do que passei aqui no serviço. Tinha um aplicativo, na verdade, uma classe que FAZIA TUDO, que sempre dava problema. Cheio de if, else, e o escambau. Então me passaram o serviço de eu corrigir um bug nessa classe. Eu olhei aquilo novamente, e pensei, desse jeito não dá e resolvi fazer um projeto separado, fiz testes. No final do projeto já tinha 22 classes, e uns 60 testes. O detalhe não é a quantidade de classes ou mesmo testes, mas sim que nesse meio tempo o teste me “salvou”, pois tinha momentos da minha implementação que quebrava algo que eu tinha que corrigir. O projeto demorou um pouco mais por causa dos testes, mas pelo menos , ou por enquanto, esse projeto está livre dos problemas enfrentados aqui no serviço e que já tomou tempo de vários desenvolvedores.
Então pessoal, vamos tentar ser mais profissionais, pois como sabemos, software sempre muda, e o testes ? Bem… este poderá um dia ser o seu Salvador!