Some useful programs for using Java in the server
*************************************************

In this directory you find some additional programs that may
be useful for examining, running, testing, or publishing Java
programs that are loaded in the server.



Installation of server-side Java tools
======================================


(1) File descriptions

Javap.java  - Java source for the Javap tool (print class content)
Java.java   - Java source for the Java tool  (invoke a class's main method)
Javai.java  - Java source for the Java tool  (evaluate class method or field)

Install.sql - Create SQL wrappers for the server-side Java tools
Drop.sql    - Drop SQL wrappers and Java classes/sources for the Java tools

SqlWrappers.java - Java source for client-side tool to generate SQL wrapper
                   scripts to publish Java classes.
SqlBatch.java    - Java source for client-side tool to send a batch of SQL
                   statements and queries to the server


(2) Installing the tools

# If necessary, remove previously installed tools.
sqlplus scott/tiger @Drop.sql

# Load the sources into the server.
loadjava -resolve -force -thin -user scott/tiger@${HOST}:5521:${ORACLE_SID} \
         Java.java Javap.java Javai.java

## Or, using the OCI driver and abbreviated options:
# loadjava -r -f -u scott/tiger Java.java Javap.java Javai.java

# Publish the tool wrappers through SQL*Plus. 
sqlplus scott/tiger @Install.sql


# The SQL Wrapper Generator and SQL Batch Processor merely have to be 
# compiled on the client
javac SqlWrappers.java SqlBatch.java


(3) A user with Java system privileges (such as the SYSDBA) needs to grant
access to members in Java classes for these tools to work, since they
make use of Java reflection.  The necessary privilege can be granted as
follows.

   CALL dbms_java.grant_permission
       ('SCOTT', 'SYS:java.lang.RuntimePermission', 'accessDeclaredMembers', '' );

(4) Invoking the tools in a database session

All tools write their output to stdout.
Thus you have to issue the following lines in your SQL*Plus session in
order to see the tool output on the server:

  set serveroutput on
  execute dbms_java.set_output(30000);

The tools can now be invoked like any other stored procedure. For example:

  CALL JAVAP('Javap');

To get a usage synopsis, call the tools with an empty string argument:

  CALL JAVAI('');


(5) Using the tools on the client

You may want to use Javap or Javai on the client. Without further ado
(assuming that "." is in your CLASSPATH):

 % javac *.java

Now you can issue (using '...' quotes under a Unix shell):

 % java Java
 % java Javap -value sqlj.tools.Sqlj
 % java Javai 'sqlj.tools.Sqlj.statusMain({"-fooBar"})'



JAVAP: Examining classes loaded in the server
=============================================

This tool works very similar to the javap tool that comes with JavaSoft's JDK.
Remember to capture stdout on the server with:
  set serveroutput on
  execute dbms_java.set_output(30000);

You call Javap as follows, providing the class name for which you want
information:

  call JAVAP('Javap');

You can also pass several class names and add options to Javap.

  call JAVAP('-all sqlj.tools.Sqlj String');

To get a usage synopsis, call JAVAP with an empty argument:
  call JAVAP('');

This will print the following summary:

Usage: Javap [-options] classname1 classname2 ...
Prints out information on one or more classes. Supported options are:
 -public    - print public memebers only
 -protected - print public and protected members
 -package   - print public, protected, and package-level members (Default)
 -private   - print all members
 -value     - print out value of public static final fields
 -throws    - print out throws information on methods
 -recurse   - print out inherited members
 -all       - synonymous with -private -throws -value

On the client you can issue the following, equivalent commands:
 % java Javap Javap
 % java Javap sqlj.tools.Sqlj String
 % java Javap -all Javap
 % java Javap



JAVA: Running a class that is loaded in the server
==================================================

This tool works very similar to the java tool that comes with JavaSoft's JDK.
Remember to capture stdout on the server with:
  set serveroutput on
  execute dbms_java.set_output(30000);

You call Java by supplying it with the class whose main method you want to invoke:

  call JAVA('Javai');

You can also pass a space-separated list of arguments to the main method.

  call JAVA('Javai "a".length()');
  call JAVA('Javap -recurse sqlj.tools.Sqlj');

However, if you want to be able to pass arguments that contain spaces, you
need to invoke an alternative style of SQL wrappers:
  JAVAX    (where 1<=X<=9 is the number of arguments passed):
For example:

  call JAVA1('Javai','"     ".length()');



Evaluating a Java method or field on a class loaded in the server
=================================================================

The JAVAI tool permits you to evaluate a Java method or constructor, or
a Java field expression.  This simplifies testing your Java code in the
server, since you need not publish your java methods before invoking them
on the SQL command line.

Remember to capture stdout on the server with:
  set serveroutput on
  execute dbms_java.set_output(30000);

You supply an expression and the evaluator returns the value (if any):

  call JAVAI('java.sql.Types.BINARY');
  call JAVAI('"ABC".length()');
  call JAVAI('"ABC".concat((new Integer(15)).toString())');

Note that only constants of type String, char and int are supported.

For array creation, the Javai tool supports only a shorthand syntax:
{elem1, ..., elemN}. The array type will be a type to which all array
elements are assignable (which may be Object, if not all elements are
in a super-subclass hierarchy). The empty array {} has type String[].

  call JAVAI('{-2,"A","$".charAt(0),Math.PI}');
  call JAVAI('new String({''1'',''2'',''3''})');
  call JAVAI('Javap.main({"Javai"})');

Note: Javai does not support Java operators (such as +, -, <, etc.),
the type cast, or array indexing. Only int, String, and char constants
are supported, but not float, double, octal, or Unicode constants.

Corresponding client-side evaluations (assuming use of a Unix shell):
 % java Javai 'java.sql.Types.BINARY';
 % java Javai '"ABC".length()';
 % java Javai '"ABC".concat((new Integer(15)).toString())';
 % java Javai '{-2,"A","$".charAt(0),Math.PI}';
 % java Javai "new String({'1','2','3'})";
 % java Javai 'Javap.main({"Javai"})';



Obtaining the value from calling a method or retrieving a field
===============================================================

The JAVAI utility that we described above is a stored procedure.  In order to
capture the (string) value returned from the Java method or the Java field,
we provide the wrapper JAVAFN. JAVAFN works exacly like JAVAI, except that
nothing is written to stdout, but instead a string value is returned at the end.
The returned string is NULL if the invoked method returns void, or if the
returned object is null. Otherwise the string is the java String representation
of the returned object.  If an error occurs during parsing or method invocation,
a SQLException is thrown.

Example:

   SELECT JAVAFN('Math.random()') FROM DUAL;

There is no command line line equivalent for JAVAFN.



Generating SQL wrappers for public static Java methods in the server
====================================================================

The SqlWrappers tool generates a SQL script for publishing the public static
methods of an existing Java class.  The script is produced on stdout.
This is useful as a first cut of a wrapper script for publishing some
existing java code.  Example:

  % java SqlWrappers Javai

Note that -by default- SqlWrappers does not generate a wrapper for the main
method.  Let's tell it to do that.

  % java SqlWrappers -main Javai

This is the 0-argument invocation of main, but we actually would like to get
the 1-argument version.  Try again.

  % java SqlWrappers -main=1 Javai

This is pretty close to what we use in the Install.sql script as well.
Note that SqlWrappers is a barebones tool - you will have to edit the names
and types in the generated script if they are not to your liking.  Also,
SqlWrappers has not (yet) heard about SQL Object Types and corresponding
Java wrapper classes.

When we published the main method from Java.java we used different names
depending on the number of arguments.  The SqlWrappers tool does not support
that, but if we publish the class into a package, we can employ overloading:

  % java SqlWrappers -package=JPack -main=0-15 Java

You can get a synopsis for SqlWrappers by invoking it without arguments.

SqlWrapper: creates SQL wrappers for Java classes.
Syntax: java SqlWrapper [options] classname [... classname]
where options is:
  -package         - generate wrappers in packages (package name derived from classname
  -package=pkgname - generate all wrapper into the package pkgname
          by default wrappers are created at the SQL top level
  -main            - generate a 0-argument wrapper for main
  -main=0,3-5,10   - generate wrappers for main with 0,3,4,5,10 arguments
          by default, no wrappers are created for main



Sending a batch of SQL statements and queries to the server
===========================================================

You can use the SqlBatch utility to send a batch of SQL statements to the
server.  The JDBC connection parameters are supplied by the sqlj.url, sqlj.user,
and sqlj.password entries in the connect.properties file.  You provide the
files containing SQL statements on the command line:

 % java SqlBatch Drop.sql

The .sql extension can optionally be dropped, and you can also list several SQL
batch files.

 % java SqlBatch Drop Install

The parser for the SQL statements is embarrassingly primitive: every statement
or query (except for the last one) must be terminated by a line with the
single character:

/

While certainly no replacement for SQL*Plus, this may be better that nothing if
you do not have a SQL batch interpreter available.
