Ajax programming with the Java Scripting API

An excerpt from 'Beginning Java SE 6 Platform: From novice to professional'

1 2 3 4 5 Page 3
Page 3 of 5

The simplest of the eval() methods are Object eval(String script) and Object eval(Reader reader). The former method is invoked to evaluate a script expressed as a String; the latter method is invoked to read a script from some other source (such as a file) and evaluate the script. Each method throws a NullPointerException if its argument is null. Listing 3 demonstrates these methods.

Listing 3. FuncEvaluator.java

// FuncEvaluator.java

import java.io.*;

import javax.script.*;

public class FuncEvaluator
{
   public static void main (String [] args)
   {
      if (args.length != 2)
      {
          System.err.println ("usage: java FuncEvaluator scriptfile "+
                              "script-exp");
          return;
      }

      ScriptEngineManager manager = new ScriptEngineManager ();
      ScriptEngine engine = manager.getEngineByName ("rhino");

      try
      {
          System.out.println (engine.eval (new FileReader (args [0])));
          System.out.println (engine.eval (args [1]));
      }
      catch (ScriptException se)
      {
          System.err.println (se.getMessage ());
      }
      catch (IOException ioe)
      {
          System.err.println (ioe.getMessage ());
      }
   }
}

FuncEvaluator is designed to evaluate the functions in a Rhino-based script file via eval(Reader reader). It also uses eval(String script) to evaluate an expression that invokes one of the functions. Both the script file and script expression are passed to FuncEvaluator as command-line arguments. Listing 4 presents a sample script file.

Listing 4. stats.js

function combinations (n, r)
{
   return fact (n)/(fact (r)*fact (n-r))
}

function fact (n)
{
   if (n == 0)
       return 1;
   else
       return n*fact (n-1);
}

The stats.js file presents combinations(n, r) and fact(n) functions as part of a statistics package. The combinations(n, r) function works with the factorial function to calculate and return the number of different combinations of n items taken r items at a time. For example, how many different poker hands in five-card draw poker (where five cards are dealt to each player) can be dealt from a full card deck?

Invoke java FuncEvaluator stats.js combinations(52,5) to discover the answer. After outputting null on the first line (to indicate that stats.js does not return a value), FuncEvaluator outputs 2598960.0 on the line below The Double value returned from combinations(52,5) indicates that there are 2,598,960 possible poker hands.

Communicating with scripts via script variables

Previously, you learned that eval() can return a script's result as an object. Additionally, the Scripting API lets Java programs pass objects to scripts via script variables, and obtain script variable values as objects. ScriptEngine provides void put(String key, Object value) and Object get(String key) methods for these tasks. Both methods throw NullPointerException if key is null, IllegalArgumentException if key is the empty string, and ClassCastException if key is not a String. Listing 5's application demonstrates put() and get().

Listing 5. MonthlyPayment.java

// MonthlyPayment.java

import javax.script.*;

public class MonthlyPayment
{
   public static void main (String [] args)
   {
      ScriptEngineManager manager = new ScriptEngineManager ();
      ScriptEngine engine = manager.getEngineByExtension ("js");

      // Script variables intrate, principal, and months must be defined (via
      // the put() method) prior to evaluating this script.

      String calcMonthlyPaymentScript = 
         "intrate = intrate/1200.0;"+
         "payment = principal*intrate*(Math.pow (1+intrate, months)/"+
         "                            (Math.pow (1+intrate,months)-1));";

      try
      {
          engine.put ("principal", 20000.0);
          System.out.println ("Principal = "+engine.get ("principal"));
          engine.put ("intrate", 6.0);
          System.out.println ("Interest Rate = "+engine.get ("intrate")+"%");
          engine.put ("months", 360);
          System.out.println ("Months = "+engine.get ("months"));
          engine.eval (calcMonthlyPaymentScript);
          System.out.printf ("Monthly Payment = %.2f\n",
                             engine.get ("payment"));
      }
      catch (ScriptException se)
      {
          System.err.println (se.getMessage ());
      }
   }
}

MonthlyPayment calculates the monthly payment on a loan via the formula MP = P*I*(1+I)N/(1+I)N-1, where MP is the monthly payment, P is the principal, I is the interest rate divided by 1200, and N is the number of monthly periods to amortize the loan. Running this application with P set to 20000, I set to 6%, and N set to 360 results in this output:

Principal = 20000.0
Interest Rate = 6.0%
Months = 360
Monthly Payment = 119.91

The script depends on the existence of script variables principal, intrate, and months. These variables (with their object values) are introduced to the script via the put() method -- 20000.0 and 6.0 are boxed into Doubles; 360 is boxed into an Integer. The calculation result is stored in the payment script variable. get() returns this Double's value to Java.

1 2 3 4 5 Page 3
Page 3 of 5