NetRexx User's Guide, version 2.02
Copyright (c) IBM Corporation, 2001. All rights reserved. ©
Draft of 22 May 2001
[previous | contents | next]

Using the NetRexxA API

As described elsewhere, the simplest way to use the NetRexx interpreter is to use the command interface (NetRexxC) with the -exec or -arg flags. There is a also a more direct way to use the interpreter when calling it from another NetRexx (or Java) program, as described here. This way is called the NetRexxA Application Programming Interface (API).

The NetRexxA class is in the same package as the translator (that is, COM.ibm.netrexx.process), and comprises a constructor and two methods. To interpret a NetRexx program (or, in general, call arbitrary methods on interpreted classes), the following steps are necessary:

  1. Construct the interpreter object by invoking the constructor NetRexxA(). At this point, the environment's classpath is inspected and known compiled packages and extensions are identified.
  2. Decide on the program(s) which are to be interpreted, and invoke the NetRexxA parse method to parse the programs. This parsing carries out syntax and other static checks on the programs specified, and prepares them for interpretation. A ‘stub’ class is created and loaded for each class parsed, which allows access to the classes through the JVM reflection mechanisms.
  3. At this point, the classes in the programs are ready for use. To invoke a method on one, or construct an instance of a class, or array, etc., the Java reflection API (in java.lang and java.lang.reflect) is used in the usual way, working on the Class objects created by the interpreter. To locate these Class objects, the API's getClassObject method must be used.

Once step 2 has been completed, any combination or repetition of using the classes is allowed. At any time (provided that all methods invoked in step 3 have returned) a new or edited set of source files can be parsed as described in step 2, and after that, the new set of class objects can be located and used. Note that operation is undefined if any attempt is made to use a class object that was located before the most recent call to the parse method.

Here's a simple example, a program that invokes the main method of the hello.nrx program's class:


  -- Try the NetRexxA interface

  options binary

  import COM.ibm.netrexx.process.NetRexxA

  

  interpreter=NetRexxA()             -- make interpreter

  

  files=['hello.nrx']                -- a file to interpret

  flags=['nocrossref', 'verbose0']   -- flags, for example

  interpreter.parse(files, flags)    -- parse the file(s), using the flags

  

  helloClass=interpreter.getClassObject(null, 'hello') -- find the hello Class

  

  -- find the 'main' method; it takes an array of Strings as its argument

  classes=[interpreter.getClassObject('java.lang', 'String', 1)]

  mainMethod=helloClass.getMethod('main', classes)

  

  -- now invoke it, with a null instance (it's static) and an empty String array

  values=[Object String[0]]

  

  loop for 10    -- let's call it ten times, for fun...

    mainMethod.invoke(null, values)

  end

Compiling and running (or interpreting!) this example program will illustrate some important points, especially if a trace all instruction is added near the top. First, the performance of the interpreter (or indeed the compiler) is dominated by JVM and other start-up costs; constructing the interpreter is expensive as the classpath has to be searched for duplicate classes, etc. Similarly, the first call to the parse method is slow because of the time taken to load, verify, and JIT-compile the classes that comprise the interpreter. After that point, however, only newly-referenced classes require loading, and execution will be very much faster.

The remainder of this section describes the constructor and the two methods of the NetRexxA class in more detail.

The NetRexxA constructor

Syntax:

  NetRexxA()

This constructor takes no arguments and builds an interpeter object. This process includes checking the classpath and other libraries known to the JVM and identifying classes and packages which are available.

The parse method

Syntax:

  parse(files=String[], flags=String[]) returns boolean

The parse method takes two arrays of Strings. The first array contains a list of one or more file specifications, one in each element of the array; these specify the files that are to be parsed and made ready for interpretation.

The second array is a list of zero or more option words; these may be any option words understood by the interpreter (but excluding those known only to the NetRexxC command interface, such as time).[1]  The parse method prefixes the nojava flag automatically, to prevent .java files being created inadvertently. In the example, nocrossref is supplied to stop a cross-reference file being written, and verbose0 is added to prevent the logo and other progress displays appearing.

The parse method returns a boolean value; this will be 1 (true) if the parsing completed without errors, or 0 (false) otherwise. Normally a program using the API should test this result an take appropriate action; it will not be possible to interpret a program or class whose parsing failed with an error.

The getClassObject method

Syntax:

  getClassObject(package=String, name=String [,dimension=int]) returns Class

This method lets you obtain a Class object (an object of type java.lang.Class) representing a class (or array) known to the interpreter, including those newly parsed by a parse instruction.

The first argument, package, specifies the package name (for example, ‘com.ibm.math’). For a class which is not in a package, null should be used (not the empty string, '').

The second argument, name, specifies the class name (for example, ‘BigDecimal’). For a minor (inner) class, this may have more than one part, separated by dots.

The third, optional, argument, specifies the number of dimensions of the requested class object. If greater than zero, the returned class object will describe an array with the specified number of dimensions. This argument defaults to the value 0.

An example of using the dimension argument is shown above where the java.lang.String[] array Class object is requested.

Once a Class object has been retrieved from the interpreter it may be used with the Java reflection API as usual. The Class objects returned are only valid until the parse method is next invoked.


Footnotes:
[1] Note that the option words are not prefixed with a ‘-’.

[previous | contents | next]