Pular para o conteúdo principal

Javascripting in Java



Linguagens dinâmicas apresentam várias vantagens sobre as linguagens compiladas. Uma dessas vantagens é a habilidade de adicionar código em tempo de execução com facilidade. Por exemplo, imagine um servidor que de alguma forma receba e processe comandos. Num ambiente Java (onde o servidor é um programa Java assim como os comandos são objetos Java) é um certo malabarismo com o Classloader para fazer isso.

http://www.javaworld.com/javaworld/jw-06-2006/jw-0612-dynamic.html?page=2


Enquanto que esse dinamismo é ainda “sustentável” para Classes, a situação é mais complicada para fragmentos de código. Nesse caso é preciso compilar uma classe Java e carregá-la. Com Javascript, a situação é outra. Uma vez que a linguagem é interpretada, é simplesmente trivial adicionar fragmentos de código. Para provar isso vou implementar um programa que imprime gráficos, para funções arbitrárias de uma variável x “real” (aliás, radicalmente arbitrárias... não irei nem mesmo validar se a entrada é de fato uma função).

Inicialmente definimos uma interface para a função. Não queremos que o código cliente seja impregnado com detalhes técnicos do funcionamento do javax.script. Queremos definir a interface mais simples possível sem comprometer o desempenho da aplicação.
public interface Function {
  double[] function(double xInit, double xfinal, double step);

  public double function(double x);
 }

Agora faremos teste com uma função bem conhecida x^2 (ou f(x) = x*x). Aqui o teste unitário da função:

/**
  * Test of function method, of class RhinoCalc.
  */
 @Test
 public void functionXQuadrado() throws Exception {
  setFunction();
  double xInit = 0.0;
  double xfinal = 10.0;
  double step = 1;
  double[] result = function.function(xInit, xfinal, step);
  assertTrue(Arrays.equals(new double[] { 0, 1, 4, 9, 16, 25, 36, 49, 64,
    81, 0 }, result));
  for (int i = 0; i < result.length; i++) {
   System.out.println(result[i]);
  }
 }
Para implementar a classe vou seguir os passos mais simples para adicionar o Javascript. Isso se resume a carregar o motor de scripts, adicionar a função e realizar a chamada necessária. Para carregar o motor de scripts:
public RhinoFunction() {
  ScriptEngineManager mgr = new ScriptEngineManager();
  jsEngine = mgr.getEngineByName("JavaScript");
 }
Atribuir uma função arbitrária:
public void setFunction(String function) throws ScriptException {
  jsEngine.eval("function f(x) { \n" + " return  " + function + ";}");
  invocableEngine = (Invocable) jsEngine;
 }
e invocar uma função:
public double function(double x) {
  try {
   return (Double) invocableEngine.invokeFunction("f", x);
  } catch (Exception e) {
   Logger.getLogger(RhinoFunction.class.getName()).log(Level.SEVERE,
     null, e);
   throw new RuntimeException(e);
  }
 }

 public double[] function(double xInit, double xfinal, double step) {
  double deltaX = xfinal - xInit;
  int size = (int) Math.ceil(deltaX / step);
  double[] result = new double[size + 1];
  int i = 0;
  for (double x = xInit; x < xfinal; x += step, i++) {
   try {
    result[i] = (Double) invocableEngine.invokeFunction("f", x);
   } catch (Exception ex) {
    Logger.getLogger(RhinoFunction.class.getName()).log(
      Level.SEVERE, null, ex);
    throw new RuntimeException(ex);
   }
  }
  return result;
 }
Agora um teste que exige mais desempenho. Podemos utilizar a classe para gerar gráficos de funções. Aqui um modelo que resume o funcionamento dessas classes: Ao pressionar o botão “plot” o seguinte método atualiza o modelo do plano cartesiano e solicita a atualização do painel.
private void plotButtonActionPerformed(java.awt.event.ActionEvent evt) {
  CartesianPanel painel = (CartesianPanel) this.graphicPanel;
  try {
   rhinoFunction.setFunction(polinomioTextField.getText());
  } catch (ScriptException e) {
   e.printStackTrace();
   JOptionPane
    .showMessageDialog(
    this,
    "O interpretador não conseguiu interpretar a função escrita.",
    "Função Inválida", JOptionPane.ERROR_MESSAGE);
  }
  painel.setFunction(rhinoFunction);
  double initialX = Double.parseDouble(initialXTextField.getText());
  double finalX = Double.parseDouble(xFinalTextField.getText());
  double initialY = Double.parseDouble(initialYTextField.getText());
  double finalY = Double.parseDouble(finalYTextField.getText());
  painel.getCartesianPlan().setDimension(initialX, finalX, initialY, finalY);
  painel.repaint();
 }
Eu adicionei alguns métodos de “zoom” com o mouse de forma que o programa tivesse mais dinamismo. Essas funcionalidades foram implementadas tanto no painel do desenho que sofre a ação como numa classe especialista “adapter” para o mouse. Isso é praticamente um completo programa de “plot” extramente simples e compacto que ilustra as facilidades do JFC e javax.script. Outras Considerações Claro que o exemplo poderia ser estendido para compreender outros conceitos e funcionalidades facilmente implementadas com JFC (como a possibilidade de impressão do gráfico), a habilidade de desenhar retângulos com a área selecionada, a possibilidade de arrastar o gráfico deslocando o ponto inicial, etc. Mas isso vai longe: uma longa caminhada do ArcTest para o Kplot... http://java.sun.com/applets/jdk/1.4/demo/applets/ArcTest/example1.html http://edu.kde.org/kmplot/

Comentários

Unknown disse…
Legal ver um exemplo da JSR-223. Tenho umas perguntas:

1 - O q vc tem contra o <pre>?
2 - Nessa linha:
CartesianPanel painel = (CartesianPanel) this.graphicPanel;
Pq o cast?
3 - Tem algum easter egg? ;-)
Rodrigo Lopes disse…
4) Por que o blogger eu não enviou sua dúvida por email?
...
Respondendo
1) Acho que o pre não fica bom, não sei. Queria que ficasse colorido como no eclipse.
2) Essa é fácil:
Se eu não usasse o cast não poderia fazer isso depois:
painel.setFunction(rhinoFunction);
3) Ainda não tenho easter egg. :(

Postagens mais visitadas deste blog

Pequeno manual do ócio em terras alemãs

  Pequeno manual do ócio em terras alemãs Como Lei alemã favorece aproveitadoras (e alguns aproveitadores que nunca tive o desprazer de conhecer)   Há algumas vias pelas quais pessoas de países em desenvolvimento migram para países como a Alemanha.   Por exemplo, é sabido que países desenvolvidos sofrem de escassez de mão-de-obra qualificada. Por esse motivo, países como a Alemanha dispõe vistos "especiais" para profissionais em demanda. Esse é o conceito do Blaukart (Blue Card) que na Alemanha se destina a profissionais salário anual seja superior a 55 mil euros ou 43 mil no caso de profissionais de áreas em alta demanda. Não há como recrutar essa mão-de-obra sem que a família desses profissionais também possa ser relocada. Então esses profissionais e seus familiares são relocados.   Além de se qualificar para essas vagas em demanda, ou ser parte direta da família qualificada, outra via possível para a imigração para o território alemão é através do matrimôni

The escape of blue eyed vampires (answer)

The island of blue eyed vampires (answer) An initial idea Each one needs to figure out if him/herself is blue eyed. They assume having blue eyes and see how the others react. A technical details There are some variations to formalize this problem using different type of logic: modal logic, temporal logic, Public Announcement Logic and so on. I believe that those kind of prove are tedious to write and read. For now, I will write a sketch to a prove but I belive the best way to prove is using an algorimthm what basically, it would be an adaptation of DPLL algorithm (Davis–Putnam–Logemann–Loveland) that uses dedutive reasoning and prove by contraction. Legend \[\begin{matrix} BlueEyed(X) :X \text{ is blue eyed.} \\ Leave(X) :X \text{ leaves.} \\ O(y) :y \text{ holds at the next (temporal) state.} \end{matrix}\] In this temporal simplified logic, we have a set of state that holds the in- formation of days, \(W = \{d_0, d_1, d_2, d3 \ldots , d_n\}\) and transition \(S : W \rightarrow

Answering: top reasons I hate living in Brazil

Yes, some guys shared a teasing topic about “Top reasons why I hate living in Brazil”: http://www.gringoes.com/forum/forum_posts.asp?TID=17615&PN=1&title=top-reasons-i-hate-living-in-brazil What is the point here? The whole text is loaded of cliclés, people that you will hardly find, etc most of time just pissing people off.   I don’t think Brazil is the best country in the world. Also, I don’t think Brazilians don’t make mistakes. Actually we do all the time but most of us really care about our mistakes specially those were pointed out. Some feel like an expatriate, alien in own country. Others reflect about how we could improve. Others  simply don’t accept teases from John Does. So, I’m actually truly bothered with people believing in a bunch of false statements (specially Brazilians) or supporting some cynical arguments disguised “sincere” criticisms . Yes, I make mistakes all the time, and as most of Brazilians, I don’t speak English. However, I will