Top Previous Next TOC Index

The Java™ Interpreter


The Java Interpreter is a part of the Oracle WebServer that interprets and executes Java and sends the HTML output to the client's browser as a Web page.

Oracle WebServer provides a set of Java classes to enable you to access the database and to generate HTML dynamically using the Java Interpreter. These classes are called the Java Web Toolkit. Using these Java classes, you can make PL/SQL calls from within your Java application, effectively combining the strengths of the two languages. This toolkit also includes a type wrapper for Java applets, to make it easy for you to store applets in the database, retrieve them through the Java Interpreter, and send them to the client for execution embedded in a Web page. You can also store and retrieve Java applets for execution on the client using the PL/SQL Agent by simply treating the applets as data.

Generally speaking, you should use Java to handle multimedia operations and to interface to objects on the net, and you should use PL/SQL for interfacing to the database. Whether this means using the PL/SQL Agent or the Java Interpreter will largely be determined by the following:

To use the Java Web Developer's Toolkit, import the following into your Java code:

Obviously, if you only want to perform some of these functions, you need only import some of these objects. For more information, see Database Access from Java, Example of Java Database Access, Dynamic HTML from Java, and Java Dynamic HTML Examples.


Database Access from Java

Using Java to call PL/SQL circumvents the PL/SQL Agent, and this has a number of consequences, among them the following:

Nonetheless, Java can do many things that PL/SQL cannot, like access local files and manipulate multimedia objects. If you need this functionality executed on the server, the Java Interpreter is the way to go.


Creating Package Wrappers

The Java Interpreter interfaces to the Oracle7 Server by running PL/SQL packages or standalone PL/SQL procedures and functions. Each package an application is to run must have a package wrapper, which is a Java class containing methods to call that package's procedures and functions. Standalone procedures and functions are all wrapped in a single wrapper. Once you have identified or created the PL/SQL packages your applications needs, you can create the package wrappers for them by running the pl2java utility as follows:

pl2java [flags] username/password[@connect-string] packagename...

This utility creates a wrapper class for each package given as an argument to the command. When your application is run, it creates an instance of this class to interface to the package. If you have standalone procedures or functions in your applications, run the pl2java utility without any package names, but using the class flag as explained below. This will create a single class wrapper for all the standalone procedures and functions you use.

Here are the component definitions:

flags
Options that control how the wrappers will be created. These are explained below.
username
The name of the Oracle database user that owns the packages.
password
The password for the Oracle user identified by username.
connect-string
The string that identifies the local or remote database where the packages are located. For local databases, this is the Oracle SID, as described in the Oracle7 Server Administrator's Guide. For remote databases, this is the SQL*Net Connect String, as described in Understanding SQL*Net.
package name...
A list of all the packages that your application references in the schema identified by username. To wrap standalone procedures and functions you must omit this component and must use the class flag to name the class wrapper that will be created. You should not include the containing schemas in the package names. It is good practice to keep all the packages, procedures, and functions you want to use in one schema.

flags

All of the flags that pl2java uses are optional, except, under certain conditions, class. Here are the descriptions of the flags:

-help
Provides help information.
-d <dir>
Sets the directory where the wrapper classes will be stored. The default is the current directory.
-package <packagename>
Sets the Java package to which the wrapper classes belong.
-class <class>
Sets the Java class to which the wrappers will belong. If the pl2java utility is run against packages, this flag is optional. Java classes based on packages inherit by default the names of the packages they encapsulate. This flag can override that default, but it only applies to the first package named in the command. If the wrappers are being created for standalone procedures and functions, then this flag is mandatory, and all procedures and functions named in the command are grouped into the single class named by this flag.
The names of the classes follow the capitalization given in the command. Since PL/SQL is not case-sensitive, this capitalization need not follow that actually given in the PL/SQL code itself.

There are certain PL/SQL datatypes that the pl2java utility cannot encapsulate. These are shown below, along with the recommended substitutes, if any:
Disallowed PL/SQL Datatype
Substitute PL/SQL Datatype
POSITIVE

BINARY INTEGER

PL/SQL table of BINARY INTEGER, NATURAL or POSITIVE

PL/SQL table of NUMBER

PL/SQL table of LONG

PL/SQL table of CHAR or VARCHAR2

PL/SQL table of BOOLEAN

PL/SQL table of NUMBER, treat 0 as false, 1 as true

ROWID

none

MSLABEL

none

PL/SQL table of ROWID

none

PL/SQL table of MSLABEL

none


Application Structure

Your Java program will be a Java class with a public static method called "main", which takes an array of strings, and various methods that are part of the wrapper classes. All the methods in the Session class throw ServerException. This exception is triggered when a database error occurs during the execution of the PL/SQL procedure or function. When invoking these methods, you should handle the exception appropriately.


The steps your application must go through are as follows:

  1. It must create an object of type Session to handle the database connection. All of the operations performed during this session must be called from within this object. When the object exits, the database connection is marked for termination by the Java garbage collector. Since connecting to the database takes time, try to minimize the number of connections by grouping into one Session object all of the operations that involve a given schema.

  2. For each PL/SQL package used in the application, it must create one instance of the packagewrapper subtype created for that PL/SQL package by the pl2java utility.

  3. For each parameter of a PL/SQL package, it must create an instance of the Java variable that matches that parameter. All classes that encapsulate PL/SQL values have toString() methods. Therefore, you can concatenate the PL/SQL values directly in Java strings using Java's "+" concatenation operation.

  4. Unlike Java and most languages, but like SQL, PL/SQL uses Nulls and Three-Valued Logic to deal with missing information. NULLs should be dealt with differently than known values. When you access a NULL from Java, it throws the NullValueException runtime exception. Therefore, you should account for this whenever a PL/SQL value may be NULL. You can do this in either of the following two ways:

You must invoke the Session setProperty method to set parameters such as ORACLE_HOME that the database session requires. For more information on this method, refer to the standard Java hypertext reference included with this document.

You should try to logoff from the database explicitly when the session is no longer needed. Although Java garbage collection disconnects the session when the Session object is exited, this does not necessarily happen right away. Java does not perform garbage collection until resources are low or the program idles. Therefore, it is better to disconnect the session to free up the database connection resource immediately.


Example of Java Database Access

This section outlines a Java program that uses a PL/SQL package to look up all employees from a database and generates a report in HTML. In our example, you have an "EMP" database table and an "Employee" PL/SQL package that looks up employee information from that table. This table and package are created by user "scott" with password "tiger" in database "HR_DB".

Here is the SQL and PL/SQL source code that defines the objects used by this example.

CREATE TABLE EMP (
emp_name VARCHAR2(30) NOT NULL,
emp_number NUMBER(10),
emp_dept VARCHAR2(30) NOT NULL
);

CREATE OR REPLACE package Employee as

  type string_table is table of varchar2(30) index by binary_integer;
type number_table is table of number(10) index by binary_integer;

  function count_employees(
dept_name in varchar2
) return number;

  procedure list_employees(
dept_name in varchar2,
employee_name out string_table,
employee_no out number_table
);

end;

CREATE OR REPLACE package body Employee as

  function count_employees(
dept_name in varchar2
) return number as
employee_count number;
begin

    select count(*)
into employee_count
from EMP
where EMP_DEPT = dept_name;

    return employee_count;

  end;

  procedure list_employees(
dept_name in varchar2,
employee_name out string_table,
employee_no out number_table
) as
i number;
cursor employee_rec(dept_name varchar2) is
select EMP_NAME, EMP_NUMBER
from EMP
where EMP_DEPT = dept_name;
begin

    i := 1;
for employee in employee_rec(dept_name) loop
employee_name(i) := employee.EMP_NAME;
employee_no(i) := employee.EMP_NUMBER;
i := i + 1;
end loop;

end;

end;

For reference, the commands themselves are considered SQL, but the code inside the packages is PL/SQL. Since PL/SQL is a superset of SQL, you can think of it all as PL/SQL.

This example uses the oracle.html package to generate dynamic HTML. That package is documented under Dynamic HTML from Java.

The main program

In this example, the program is called EmployeeReport. This program will be saved in a file called EmployeeReport.java.

import oracle.html.*;

public class EmployeeReport {

  public static void main (String args[]) {

								    HtmlHead hd = new HtmlHead("Employee Listing");
HtmlBody bd = new HtmlBody();
HtmlPage hp = new HtmlPage(hd, bd);
hp.printHeader();
hp.print();

  }
}

Generating the Java Wrapper Class for the Employee Package

To access the Employee package, you must generate a Java wrapper class for it. This encapsulates the package as a Java class. The functions and procedures in the package will appear as methods in the wrapper class under the same names.

PL/SQL datatypes are encapsulated by Java objects. For example, a PL/SQL VARCHAR2 string is encapsulated by a Java PStringBuffer object, and a PL/SQL number is encapsulated by a Java PDouble object.

To generate the Java class wrapper for Employee package, execute the following command at a command prompt:

pl2java scott/tiger@HR_DB Employee

This generates the class wrapper Employee.class in the current directory. The class will have 1 constructor and 2 methods for the Employee package:

public class Employee {

  public Employee(Session session) { ... }

  public PDouble count_employees(PStringBuffer dept_name)
throws ServerException { ... }

  public void list_employees(PStringBuffer dept_name,
PStringBuffer employee_name[],
PDouble employee_number[])
throws ServerException { ... }
}

Notice that the constructor takes a Session object as a parameter to encapsulate the database connection. This is because each time a PL/SQL package, procedure, or function is accessed in a session, it is instantiated. In effect, a copy is created that is the private property of that session. This gives the package a stable state for that session, while leaving it free to have another state when called by another session.


Overriding Default Value Sizes

When a PL/SQL function returns a value whose size is variable - for example VARCHAR2, LONG, RAW, or LONG RAW - the size of the value is set by default to 255 bytes. In the wrapper class, you may change the default size by setting the following variable for the PL/SQL function in question:

<function name>_<overload number>_return_length

The overload number is the number of other functions that exist with the same name as this one. To find out about overloading of functions in PL/SQL, see Overloading Subprograms. For more information on overload numbers specifically, see the PL/SQL User's Guide and Reference. You can find out what the overload number of a function is by using the Oracle7 Server standard package dbms_describe, as covered in the Oracle7 Server Administrator's Guide. For non-overloaded functions, the overload number is 0.

For example, assume the following PL/SQL package:

CREATE OR REPLACE package Employee as 
function employee_name (
employee_number in number
) return varchar2;

END;

By default, the length of the return value is 255 bytes. You can change this using the code shown below:

public class EmployeeReport { 
public static void main(String args[]) {
Session session = new Session("scott", "tiger", "HR_DB");
Employee employee = new Employee(session);
PDouble pEmployeeNumber = new PDouble((double)12345);
// Set VARCHAR2 return length for function employee_name to 50 employee.employee_name_0_return_length = 50;
System.out.println("Employee ID: " + pEmployeeNumber +
" name: " + employee.employee_name(pEmployeeNumber)); }
}

Similarly, when a PL/SQL function returns a PL/SQL table, its default length is 40. You can change that length by changing the following variable in the wrapper class:

<function name>_<overload number>_return_arraylength

Making a connection to the database

The first thing that you have to do in the EmployeeReport program is to connect to a database. You do this by using the following code to create a Session object:

import oracle.html.*;
import oracle.rdbms.*; // ADD: import Oracle classes which deal //with database

public class EmployeeReport {

  public static void main (String args[]) {

    HtmlHead hd = new HtmlHead("Employee Listing");
HtmlBody bd = new HtmlBody();
HtmlPage hp = new HtmlPage(hd, bd);
hp.printHeader();

    

    // ADD: defines Oracle session properties like ORACLE_HOME
Session.setProperty("ORACLE_HOME", "/user/oracle");
Session.setProperty("TNS_ADMIN", "/user/oracle/network/admin");

    // ADD: creates a database session and logon
Session session;
try {
session = new Session("scott", "tiger", "HR_DB");
} catch (ServerException e) {
bd.addItem(new SimpleItem("Logon fails: " + e.getSqlerrm()));
hp.print();
return;
}
hp.print()
}
}

To handle any errors raised, put the operation in a "try {...} catch (...) {... }" block and trap any ServerExceptions.

Invoking the Employee package

To invoke the Employee package, you need to create a new instance of the corresponding wrapper class. Then you can call the procedures and functions in the package by invoking the methods in the wrapper class. Add the following code to the program:

import oracle.html.*;
import oracle.rdbms.*;
import oracle.plsql.*; // ADD: import Oracle classes which deal //with PL/SQL data types

public class EmployeeReport {

    public static void main (String args[]) {

    HtmlHead hd = new HtmlHead("Employee Listing");
HtmlBody bd = new HtmlBody();
HtmlPage hp = new HtmlPage(hd, bd);
hp.printHeader();

    Session.setProperty("ORACLE_HOME", "/user/oracle");
Session.setProperty("TNS_ADMIN", "/user/oracle/network/admin");

    Session session;
try {
session = new Session("scott", "tiger", "HR_DB");
} catch (ServerException e) {
bd.addItem(new SimpleItem("Logon fails: " + e.getSqlerrm()));
hp.print();
return;
}

    // ADD: create a new instance of Employee package
Employee employee = new Employee(session);

    // ADD: find the department name from the input parameter
String deptName = null;
if ((args.length < 1) || !args[0].startsWith("DEPT=")) {
bd.addItem(new SimpleItem("No department name given"));
hp.print();
return;
} else {
deptName = args[0].substring(5);
}

    // ADD: create objects to encapsulate PL/SQL values that are
// used as parameters
PStringBuffer pDeptName = new PStringBuffer(30, deptName);
PStringBuffer pEmployeeName[];
PDouble pEmployeeNumber[];
PDouble pEmployeeCount;

    // ADD: print report header
bd.addItem("Department " + pDeptName + ":")
.addItem(SimpleItem.Paragraph);

    // ADD: call Employee package to count the number of employees in
// the department
try {
pEmployeeCount = employee.count_employees(pDeptName);
} catch (ServerException e) {
bd.addItem("Fail to retrieve employee information for department " +
deptName + ": " + e.getSqlerrm());
hp.print();
return;
}
int employeeCount = (int)pEmployeeCount.doubleValue();
if (employeeCount == 0) {
bd.addItem("No employee found under department " + deptName);
hp.print();
return;
}

    // ADD: allocate the arrays for employee names and numbers
pEmployeeName = new PStringBuffer[employeeCount];
pEmployeeNumber = new PDouble[employeeCount];

    // ADD: allocate the buffers to retrieve employee information
for(int i = 0; i < employeeCount; i++) {
// max length of employee name is 30 (characters)
pEmployeeName[i] = new PStringBuffer(30);
pEmployeeNumber[i] = new PDouble();
}

    // ADD: call Employee package to look up employees in the dept
try {
employee.list_employees(pDeptName, pEmployeeName, pEmployeeNumber);
} catch (ServerException e) {
bd.addItem("Fail to retrieve employee information for department " +
deptName + ": " + e.getSqlerrm());
hp.print();
return;
}

    // ADD: generate report
DynamicTable tab = new DynamicTable(2);
TableRow row = new TableRow();
row.addCell(new TableHeaderCell("Employee Name"))
.addCell(new TableHeaderCell("Employee Number"));
tab.addRow(row);

for (int i = 0; i < employeeCount; i++) {
row = new TableRow();
if (pEmployeeNumber[i].isNull())
row.addCell(new TableDataCell(pEmployeeName[i].toString()))
.addCell(new TableDataCell("new employee"));
else
row.addCell(new TableDataCell(pEmployeeName[i].toString()))
.addCell(new TableDataCell(pEmployeeNumber[i].toString()));
tab.addRow(row);
}
hp.addItem(tab);
hp.print();

    // ADD: logoff from database
try {
session.logoff();
} catch (ServerException e);
}
}

There are a few aspects of the preceding code worth pointing out:

  1. You must create an instance of Employee package before you can invoke the procedures and functions in it. When initiating the package, you need to specify the database session where the instance of the package is to be created.

  2. Before you invoke a PL/SQL procedure or function, you have to create Java instance variables for the PL/SQL values that are to be used as parameters (like "pDeptName" in the above example). PL/SQL tables map to Java arrays. Remember to allocate the array as well as the individual elements in the array.

  3. When you access a PL/SQL value, remember that the value may be NULL unless database constraints prevent this. If the value is NULL, and you try to retrieve it using the value methods (such as doubleValue() of PDouble), it throws a NullValueException runtime condition. It is better to ensure the value is not NULL before retrieving the value or to try the NullValueException.

  4. All classes that encapsulate PL/SQL values have toString() methods and therefore can be concatenated. For an example of this, see the report-header-generation section above.

  5. You should try to logoff from the database explicitly when the session is no longer needed. When a session is no longer needed, the session is disconnected when Java performs garbage collection. Java does not, however, guarantee that any garbage objects will be collected immediately when they become garbage. In fact, Java's garbage collector waits until the program idles, which for a busy Web site could be infrequent, or until resources are low, before it collects garbage objects. Therefore, it is better to issue a disconnect statement to free up database resources explicitly.


Dynamic HTML from Java

To generate dynamic HTML from within Java, you create various objects that use the interface IHtmlItem. All classes that generate dynamic HTML implement this interface, which has two simple methods: toHTML and print. Both of these methods produce the content of the object as HTML, but toHTML returns it as a string, whereas print sends it to system output. Therefore, you use toHTML when you want the resulting HTML to be further processed by another method and use print when you want to output it. In effect, you build your Web page in a buffer with toHTML and flush the buffer with print.

The oracle.html package provides a standard set of classes based on HTML2, HTML3, and popular browser-specific extensions. You are not limited to these, however. You can easily create your own customizable HTML classes by deriving them from the CompoundItem or Container classes. The oracle.html package also has the intelligence to generate output that is optimized for the browser at hand. For example, a browser that does not support tables will get table data in the form of preformatted strings.

In some cases, interfaces have been used to specify the attributes of HTML tags. This was done to simplify cases where tag assignments can be complex or where similar arguments are used by several types of tags.

If you have a body of HTML you want to use repeatedly, you can encapsulate it in an object of class Compounditem and thereafter treat it as a single HTMLitem.

The HTML tags that you can dynamically generate using the supplied objects are listed below:
HTML FEATURE

JAVA OBJECTS THAT GENERATE

headings

HTMLHead

page breaks

HTMLPage

main body of page

HTMLBody

Comments

Comment

links

Link

anchors

Anchor

client- side Java applets

Applet

checkboxes

CheckBox

forms

Form

lists

Java classes exist for various types

frames

Frameset; Frame

hidden fields

Hidden

GIF graphics

Image

select options

Select; Option

passwords

PasswordField

radio buttons

Radio

tables

Table; DynamicTable; TableRow; TableCell; TableDataCell; TableHeaderCell; TableRowCell

text areas

TextArea; TextField

As you can see, the Java objects that generate the main structural HTML tags begin with HTML; others are chiefly named for the tags they generate.

The general procedure is to use the first three objects to define the basic structure of your generated Web page to then to use the AddItem method to add HTMLItems to the body.


Java Dynamic HTML Examples

Here are examples of how to dynamically generate some HTML text using The Java Interpreter.

The following is a basic Java program that produces an HTML page whose title and content are both the famous "Hello World!":

import oracle.html.*;

public class HelloWorld {

public static void main (String args[]) {

// Create an HtmlHead Object titled "Hello World!"
HtmlHead hd = new HtmlHead("Hello World!");

// Create an HtmlBody Object
HtmlBody bd = new HtmlBody();

// Create an HtmlPage Object
HtmlPage hp = new HtmlPage(hd, bd);

// Adds a simple string "Hello World" in this page
bd.addItem("Hello World!");

// Print out the content of this Page
hp.print();
}

}

The following Java code creates an HTML anchor:

// Creates an anchor
Anchor anchor = new Anchor("expire_date", new SimpleItem("Expire Date: 02/96"));

The following Java code creates an HTML form:

// Create a form object
Form form = new Form("GET", "http://www.myhom.com/wrb/doit");

// Create a TextField object and add it to the form
form.addItem(new TextField("textfield"));

// Add the form object to the HtmlBody object
bd.addItem(form);

The following Java code creates an HTML table. To make this example realistic, we have added some user-defined functions:

// Some user-defined functions
Product product = getFirstProduct();

// create a dynamic table with 2 columns
DynamicTable tab = new DynamicTable(2);

// create the rows and add them to the table
TableRow rows[] = new TableRow[NUM_ROWS];

for (int i=0; i< NUM_ROWS; i++) {
// allocate TableRow
rows[i] = new TableRow();
// populate row with data
rows[i].addCell(new TableHeaderCell(product.getProductID()))
.addCell(new TableDataCell(product.getProductDescription()))
// add them to Table
tab.addRow(rows[i]);
}

The following Java code creates an HTML menu:

// Create a MenuList Object
MenuList menulist = new MenuList();
// Add new items to the list
menulist.addItem(new SimpleItem("Menu Item 1"))
.addItem(new SimpleItem("Menu Item 2"));
// Add the list object to the body
bd.addItem(menulist);

The following Java code creates an HTML definition list, encapsulated in a Container object:

// Creates a new Container Object
Container dterms = new Container();
dterms.addItem(new SimpleItem("DefTerm1.1"));
dterms.addItem(new SimpleItem("DefTerm1.2"));
DefinitionList dl = new DefinitionList();
// Creates a new Definition List Object, note the first argument
dl.addDef(dterms, new SimpleItem("Definition1"));

The following Java code creates an HTML ordered list:

// Create a OrderedList Object
OrderedList orderedlist = new OrderedList();
// Add new items to the list
orderedlist.addItem(new SimpleItem("Ordered Item 1"))
.addItem(new SimpleItem("Ordered Item 2"));
// Add the list object to the body (assuming it already exists)
bd.addItem(orderedlist);

The following Java code encapsulates a group of HTML tags as a single component that can be used repeatedly in a page:

// Create a new CompoundItem object
CompoundItem compoundItem = new CompoundItem();
// Set the default text attribute of all items in Compound Item
// Note that this operation cannot be done with a <b>Container</b>
compoundItem.setItal();
// Add a SimpleItem and a TextArea to the CompoundItem
compoundItem.addItem(new Simpleitem("How are you?").setBold())
.addItem(new TextArea("response", 30, 10));
// Add the CompoundItem to the body object (assuming it's been created)
bd.addItem(compoundItem);

The following Java code specifies an applet of Java bytecode to be included in the Web page output for execution on the client's browser.

// Create a new Applet object with the following attributes:
// Applet file name: "NervousText.class"
// Width of Applet Window: 400
// Height of Applet Window: 75
// Parameter: Name="text", Value="This is an applet test"
Applet applet = new Applet("NervousText.class", 400, 75);
applet.addParam("text", "This is an applet test.");


Click Here to Go to the top of the section.

Click Here to Go to the previous topic.

Click Here to Go to the next topic.

Click here to Go to the Table of Contents.

Click here to Go to the Index.


This document was last modified at 03:55pm PST on March 27, 1996.

To report any problems or comments, e-mail Oracle WebServer Documentation.