Oracle8i
Java Developer's Guide
Release 8.1.5 A64682-01 |
|
Virtually all JServer developers will use the loadjava
and dropjava tools that we discussed in previous chapters. This
appendix presents the details of these two tools. It also covers the finer
points of the way resolvers work in JServer. The individual books for Oracle8i
Java Support (Oracle8i Java Stored Procedures and Developer's Guide,
SQLJ Developer's Guide and Reference, Enterprise JavaBeans and CORBA Developer's
Guide, Oracle8i JDBC Developer's Guide and Reference, and Oracle8i
JPublisher User's Guide) all include enough information about loadjava
and dropjava to support their particular areas. The information
presented in this chapter was extracted from Chapter 6 of the Oracle8i
Enterprise JavaBeans and CORBA Developer's Guide, which also includes
information on tools specific to EJB and CORBA.
Unlike a conventional Java virtual machine, which compiles and loads Java files, the Aurora Java virtual machine compiles and loads schema objects. The three kinds of Java schema objects are:
To make a class file runnable by the Aurora Java virtual
machine, you use the loadjava tool to create a Java class schema
object from the class file or the source file and load it into a schema.
To make a resource file accessible to the Aurora Java virtual machine,
you use loadjava to create and load a Java resource schema object
from the resource file.
The dropjava tool does the reverse of the loadjava
tool; it deletes schema objects that correspond to Java files. You should
always use dropjava to delete a Java schema object that was created
with loadjava; dropping by means of SQL DDL commands will not
update auxiliary data maintained by loadjava and dropjava.
You must load resource files with loadjava. If you
create .class files outside the database with a conventional compiler,
then you must load them with loadjava. The alternative to loading
class files is to load source files and let the Oracle8 i system
compile and manage the resulting class schema objects. In the current Oracle8
i release, most developers will find that compiling and debugging most
of their code outside the database and then loading .class files
to debug those files which must be tested inside the database, is the most
productive approach. For a particular Java class, you can load either its
.class file or its .java file, but not both.
loadjava accepts JAR files that contain either source
and resource files or class and resource files (recall that you can load
a class's source or its class file but not both). When you pass loadjava
a JAR file or a ZIP file, loadjava opens the archive and loads
its members individually; there is no JAR or ZIP schema object. A file
whose content has not changed since the last time it was loaded is not
re-loaded, therefore there is little performance penalty for loading
JARs. Loading JAR files is the simplest and most foolproof way to
use loadjava.
It is illegal for two schema objects in the same schema to define the same class. For example, suppose a.java defines class x and you want to move the definition of x to b.java. If a.java has already been loaded, then loadjava will reject an attempt to load b.java (which also defines x). Instead, do either of the following:
Many Java classes contain references to other classes. A
conventional Java virtual machine searches for classes in the directories,
ZIP files, and JARs named in the CLASSPATH. The Aurora Java virtual machine,
by contrast, searches schemas for class schema objects. Each Oracle8
i class has a resolver spec, which is the Oracle8 i counterpart
to the CLASSPATH. For a hypothetical class alpha, its resolver
spec is a list of schemas to search for classes alpha uses. Notice
that resolver specs are per-class, whereas in a classic Java virtual machine,
CLASSPATH is global to all classes.
In addition to a resolver spec, each class schema object has a list of interclass reference bindings. Each reference list item contains a reference to another class, and one of the following:
An Oracle8 i facility called the resolver maintains
reference lists. For each interclass reference in a class, the resolver
searches the schemas specified by the class's resolver spec for a valid
class schema object that satisfies the reference. If all references are
resolved, the resolver marks the class valid. A class that has never
been resolved, or has been resolved unsuccessfully, is marked invalid.
A class that depends on a schema object that becomes invalid is also marked
invalid at the same time; in other words, invalidation cascades upward
from a class to the classes that use it and the classes that use them,
and so on. When resolving a class that depends on an invalid class, the
resolver first tries to resolve the dependency because it may be marked
invalid only because it has never been resolved. The resolver does not
re-resolve classes that are marked valid.
A class developer can direct loadjava to resolve
classes, or can defer resolution until run time. (The resolver runs automatically
when a class tries to load a class that is marked invalid.) It is best
to resolve before run time to learn of missing classes early; unsuccessful
resolution at run time produces a "class not found" exception. Furthermore,
run-time resolution can fail for lack of database resources if the tree
of classes is very large.
loadjava has two resolution modes (in addition to "defer resolution"):
-andresolve -resolver "((* definer's_schema) (* public) (* -))"
A will be resolved before B is loaded; although B is not
present, A will be marked valid because the third element of the resolver
spec says to mark A valid even though a class it refers to (B) cannot be
found. After A, B will be loaded, resolved, and marked valid (assuming
its dependencies are satisfied). If you then execute A, it will not be
re-resolved because it is marked valid. But if A calls B, you may get an
unpredictable exception because A has not been successfully resolved with
respect to B.
Note: Like a Java compiler, loadjava resolves references to classes but not to resources; be sure to correctly load the resource files your classes need. |
If you can, it is best to defer resolution until all classes
have been loaded; this technique avoids the situation in which the resolver
marks a class invalid because a class it uses has not yet been loaded.
The schema object digest table is an optimization that is
usually invisible to developers. The digest table enables loadjava
to skip files that have not changed since they were last loaded. This feature
improves the performance of makefiles and scripts that invoke loadjava
for collections of files, only some of which need to be re-loaded. A re-loaded
archive file might also contain some files that have changed since they
were last loaded and some that have not.
The loadjava tool detects unchanged files by maintaining
a digest table in each schema. The digest table relates a file name to
a digest, which is a shorthand representation of the file's content
(a hash). Comparing digests computed for the same file at different times
is a fast way to detect a change in the file's content--much faster than
comparing every byte in the file. For each file it processes, loadjava
computes a digest of the file's content and then looks up the file name
in the digest table. If the digest table contains an entry for the file
name that has the identical digest, then loadjava does not load
the file because a corresponding schema object exists and is up to date.
If you invoke loadjava with the -verbose option, then
it will show you the results of its digest table lookups.
Normally, the digest table is invisible to developers because
loadjava and dropjava keep it synchronized with schema
object additions, changes, and deletions. For this reason, always use dropjava
to delete a schema object that was created with loadjava, even
if you know how to drop a schema object with DDL. If the digest table becomes
corrupted (loadjava does not update a schema object whose file
has changed), use loadjava's -force option to bypass
the digest table lookup.
Loading a source file creates or updates a Java source schema object and invalidates the class schema object(s) previously derived from the source. (If the class schema objects don't exist, loadjava creates them.) loadjava invalidates the old class schema objects because they were not compiled from the newly loaded source. Compilation of a newly loaded source, called for instance A, is automatically triggered by any of the following conditions:
To force compilation when you load a source file, use the
loadjava -resolve or -andresolve option.
The compiler writes error messages to the predefined USER_ERRORS
view; loadjava retrieves and displays the messages produced by
its compiler invocations. See the Oracle8i
Reference for a description of this table.
The compiler recognizes two options which are described in
this section, encoding and online. There are two ways
to specify options to the compiler. If you run loadjava with one
of the resolve options (which may trigger compilation), then you can specify
compiler options on the command line.
You can additionally specify persistent compiler options
in a per-schema database table called JAVA$OPTIONS which you create
as described shortly. You can use the JAVA$OPTIONS table for default
compiler options, which you can override selectively with a loadjava
command-line option.
Note: A command-line option both overrides and clears the matching entry in the JAVA$OPTIONS table. |
A JAVA$OPTIONS row contains the names of source schema objects to which an option setting applies; you can use multiple rows to set the options differently for different source schema objects. The compiler looks up options in the JAVA$OPTIONS table when it has been invoked without a command line (that is, by the class loader), or when the command line does not specify an option. When compiling a source schema object for which there is neither a JAVA$OPTIONS entry nor a command line value for an option, the compiler assumes a default value as follows:
You can set JAVA$OPTIONS entries by means of the following functions and procedures, which are defined in the database package DBMS_JAVA:
The name parameter is a Java package name, or a
fully qualified class name, or the empty string. When the compiler searches
the JAVA$OPTIONS table for the options to use for compiling a
Java source schema object, it uses the row whose name most closely
matches the schema object's fully qualified class name. A name
whose value is the empty string matches any schema object name.
The option parameter is either 'online'
or 'encoding'. For the values you can specify for these
options, see the Oracle8i SQLJ Developer's
Guide and Reference .
A schema does not initially have a JAVA$OPTIONS table. To create a JAVA$OPTIONS table, use the DBMS_JAVA package's java.set_compiler_option procedure to set a value; the procedure will create the table if it does not exist. Specify parameters in single quotes. For example:
SQL> execute dbms_java.set_compiler_option('x.y', 'online', 'false');
Table 4-1 represents a hypothetical JAVA$OPTIONS database table. Because the table has no entry for the encoding option, the compiler will use the default or the value specified on the command line. The online options shown in the table match schema object names as follows:
JAVA$OPTIONS Entries |
Match Examples | ||
---|---|---|---|
Name | Option | Value | |
a.b.c.d |
online |
true |
a.b.c.d, a.b.c.d.e |
a.b |
online |
false |
a.b, a.b.c.x |
(empty string) |
online |
true |
a.c, x.y |
The loadjava tool creates schema objects from files
and loads them into a schema. Schema objects can be created from Java source
files, class files, and resource files, and the same kinds of files in
uncompressed ZIP and Java archives (JARs). loadjava can also create
schema objects from SQLJ files; the Oracle8i
SQLJ Developer's Guide and Reference describes how to use loadjava
with SQLJ. You must have the CREATE PROCEDURE privilege to load into your
schema, and the CREATE ANY PROCEDURE privilege to load into another schema.
loadjava {-user | -u} <user>/<password>[@<database>] [options] <file>.java | <file>.class | <file>.jar | <file>.zip | <file>.sqlj | <resourcefile>} ... [{-a | -andresolve}] [-debug] [{-d | -definer}] [{-e | -encoding} <encoding_scheme>] [{-f | -force}] [{-g | -grant} {<user> | <role>}[,{<user> | <role>}]...] [{-o | -oci8}] [-oracleresolver] [{-r | -resolve}] [{-R | -resolver} "resolver_spec"] [{-S | -schema} <schema>] [{-s | -synonym}] [{-t | -thin}] [{-v | -verbose}]
Table 4-2 summarizes the loadjava arguments. If you execute loadjava multiple times specifying the same files and different options, the options specified in the most recent invocation hold. There are two exceptions:
Argument | Description |
---|---|
<filenames> |
You can specify any number and combination of .java, .class, .sqlj, .jar .zip, and resource file name arguments in any order. JAR and ZIP files must be uncompressed. |
-andresolve |
Directs loadjava to compile sources if they have been loaded and to resolve external references in each class as it is loaded. -andresolve and -resolve are mutually exclusive; if neither is specified, then loadjava loads source or class files but does not compile or resolve them. |
-debug |
Directs the Java compiler to generate debug information; equivalent to javac -g. |
-definer |
By default, class schema objects run with the privileges of their invoker. This option confers definer (the developer who invokes loadjava) privileges upon classes instead. (This option is conceptually similar to the Unix setuid facility.) |
-encoding |
Identifies the source file encoding for the compiler, overriding the matching value, if any, in the JAVA$OPTIONS table. Values are the same as for the javac -encoding option. If you do not specify an encoding on the command line or in a JAVA$OPTIONS table, the encoding is assumed to be latin1. The -encoding option is relevant only when loading a source file. |
-force |
Forces files to be loaded even if they match digest table entries. |
-grant |
Grants the EXECUTE privilege on loaded classes to the listed users and/or roles. (To call the methods of a class, users must have the EXECUTE privilege.) Any number and combination of user and role names can be specified, separated by commas but not spaces (-grant Bob,Betty not -grant Bob, Betty). Note: -grant is a "cumulative" option; users and roles are added to the list of those with the EXECUTE privilege. To remove privileges, either drop and reload the schema object with the desired privileges or change the privileges with the SQL REVOKE command. To grant the EXECUTE privilege on an object in someone else's schema requires that the original CREATE PROCEDURE privilege was granted with WITH GRANT options. |
-oci8 |
Directs loadjava to communicate with the database using the OCI JDBC driver. -oci8 and -thin are mutually exclusive; if neither is specified -oci8 is used by default. Choosing -oci8 implies the syntax of the -user value. |
-oracleresolver |
Shorthand for: -resolver '((* definer's_schema) (* public))' -oracleresolver is the default and is mutually exclusive with -resolver. -oracleresolver detects missing classes immediately. Use -oracleresolver (or do not specify -resolver) except when you want to test a class regardless of its unresolved references. |
-resolve |
Compiles (if necessary) and resolves external references in classes after all classes on the command line have been loaded. -andresolve and -resolve are mutually exclusive; if neither is specified, then loadjava loads files but does not compile or resolve them. |
-resolver |
Specifies an explicit resolver spec, which is bound to the newly loaded classes. -resolver is mutually exclusive with -oracleresolver. See "resolver" in this section for details. |
-schema |
Designates the schema where schema objects are created. If not specified, the logon schema is used. To create a schema object in a schema that is not your own, you must have the CREATE PROCEDURE or CREATE ANY PROCEDURE privilege. |
-synonym |
Creates a PUBLIC synonym for loaded classes making them accessible outside the schema into which they are loaded. To specify this option, you must have the CREATE PUBLIC SYNONYM privilege. If -synonym is specified for source files, classes compiled from the source files are treated as if they had been loaded with -synonym. |
-thin |
Directs loadjava to communicate with the database using the thin JDBC driver. -oci8 and -thin are mutually exclusive; if neither is specified, then -oci8 is used by default. Choosing -thin implies the syntax of the -user value. |
-user |
Specifies a user, password, and database connect string; the files will be loaded into this database instance. The argument has the form <username>/<password>[@<database>]. |
-verbose |
Directs loadjava to emit detailed status messages while running. Use -verbose to learn when loadjava does not load a file because it matches a digest table entry. |
This section describes the details of loadjava arguments whose behavior is more complex than the summary descriptions contained in Table 4-2.
You can specify as many .class, .java,
.sqlj, .jar, .zip, and resource files as you
like, in any order. If you specify a JAR or ZIP file, then loadjava
processes the files in the JAR or ZIP; there is no JAR or ZIP schema object.
If a JAR or ZIP contains a JAR or ZIP, loadjava does not process
them.
The best way to load files is to put them in a JAR or ZIP
and then load the archive. Loading archives avoids the resource schema
object naming complications described later in this section. If you have
a JAR or ZIP that works with the JDK, then you can be sure that loading
it with loadjava will also work, without having to learn anything
about resource schema object naming.
Schema object names are slightly different from file names,
and loadjava names different types of schema objects differently.
Because class files are self-identifying (they contain their names), loadjava's
mapping of class file names to schema object names is invisible to developers.
Source file name mapping is also invisible to developers; loadjava
gives the schema object the fully qualified name of the first class defined
in the file. JAR and ZIP files also contain the names of their files; however,
resource files are not self identifying. loadjava generates Java
resource schema object names from the literal names you supply as
arguments (or the literal names in a JAR or ZIP file). Because running
classes use resource schema objects, it is important that you specify resource
file names correctly on the command line, and the correct specification
is not always intuitive. The surefire way to load individual resource files
correctly is:
Run loadjava from the top of the package
tree and specify resource file names relative to that directory. (The "top
of the package tree" is the directory you would name in a Java CLASSPATH
list.)
If you do not want to follow this rule, observe the details of resource file naming that follow. When you load a resource file, loadjava generates the resource schema object name from the resource file name as literally specified on the command line. Suppose, for example you type:
% cd /home/scott/javastuff % loadjava options alpha/beta/x.properties % loadjava options /home/scott/javastuff/alpha/beta/x.properties
Although you have specified the same file with a relative
and an absolute path name, loadjava creates two schema
objects, one called alpha/beta/x.properties, the other ROOT/home/scott/javastuff/alpha/beta/x.properties.
(loadjava prepends ROOT because schema object names cannot
begin with the "/" character; however, that is an implementation
detail that is unimportant to developers.) The important point is that
a resource schema object's name is generated from the file name as entered.
Classes can refer to resource files relatively (for example,
b.properties) or absolutely (for example, /a/b.properties).
To ensure that loadjava and the class loader use the same name
for a schema object, follow this rule when loading resource files:
Enter the name on the command line that the class passes
to getResource() or getResourceAsString().
Instead of remembering whether classes use relative or absolute resource names and changing directories so that you can enter the correct name on the command line, you can load resource files in a JAR as follows:
% cd /home/scott/javastuff % jar -cf alpharesources.jar alpha/*.properties % loadjava options alpharesources.jar
Or, to simplify further, put both the class and resource files in a JAR, which makes the following invocations equivalent:
% loadjava options alpha.jar % loadjava options /home/scott/javastuff/alpha.jar
The two loadjava commands in this example make the point that you can use any pathname to load the contents of a JAR file. Note as well that even if you did execute the redundant commands shown above, loadjava would realize from the digest table that it did not need to load the files twice. That means that re-loading JAR files is not as time-consuming as it might seem even when few files have changed between loadjava invocations.
The -definer option is identical to definer's rights in stored procedures and is conceptually similar to the Unix setuid facility; however, whereas setuid applies to a complete program, you can apply -definer class by class. Moreover, different definers may have different privileges. Because an application may consist of many classes, you must apply -definer with care to achieve the results desired, namely classes that run with the privileges they need but no more. For more information on definer's rights, see the Oracle8i Java Stored Procedures Developer's Guide.
Use -resolve to force loadjava to compile (if necessary) and resolve a class that has previously been loaded. It is not necessary to specify -force because resolution is performed after, and independently of, loading; however, note that -andresolve does not resolve previously loaded classes.
This option associates an explicit resolver spec with the
class schema objects that loadjava creates or replaces.
A resolver spec consists of one or more items, each of which consists of a name spec and a schema spec expressed in the following syntax:
"((name_spec schema_spec) [(name_spec schema_spec)] ...)"
The resolution operation interprets a resolver spec item
as follows:
When looking for a schema object whose name matches the
name spec, look in the schema named by the partner schema spec.
The resolution operation searches schemas in the order in which the resolver spec lists them. For example,
-resolver '((* SCOTT) (* PUBLIC))'
Search for any reference first in SCOTT and then in
PUBLIC. If a reference is not resolved, then mark the referring class invalid
and display an error message; in other words, call attention to missing
classes.
For a developer named Scott, this resolver spec is equivalent
to the -oracleresolver spec.
The following example:
-resolver "((* SCOTT) (* PUBLIC) (my/gui/* -))"
Search for any reference first in SCOTT and then in PUBLIC. If the reference is not found, and is to a class in the package my.gui then mark the referring class valid, and do not display an error; in other words, ignore missing classes in this package. If the reference is not found and is not to a class in my.gui, then mark the referring class invalid and produce an error message.
The permissible forms of @<database> depend on whether you specify -oci8 or -thin; -oci8 is the default.
Here are examples of loadjava commands:
loadjava -u scott/tiger -resolve -schema TEST ServerObjects.jar
loadjava -thin -u scott/tiger@dbhost:5521:orcl \ -andresolve alpha.class beta.props
loadjava -thin -schema test -u scott/tiger@localhost:5521:orcl \ -grant Betty,Bob alpha.class
The dropjava tool is the converse of loadjava.
It transforms command-line file names and uncompressed JAR or ZIP file
contents to schema object names, then drops the schema objects and deletes
their corresponding digest table rows. You can enter .java, .class,
.sqlj, .zip, .jar, and resource file names on
the command line in any order. The Oracle8i
SQLJ Developer's Guide and Reference describes how to use loadjava
and dropjava with SQLJ.
Dropping a class invalidates classes that depend on it, recursively
cascading upwards. Dropping a source drops classes derived from it.
dropjava {-u | -user} <user>/<password>[@<database>] [options] {<file>.java | <file>.class | file.sqlj | <file>.jar | <file.zip> | <resourcefile>} ... [{-o | -oci8}] [{-S | -schema} <schema>] [{-t | -thin}] [{-v | -verbose}]
Table 4-3 summarizes the
dropjava arguments.
dropjava interprets most file names as loadjava does:
If a file name has another extension or no extension, then
dropjava interprets the file name as a schema object name and
drops all source, class, and resource objects that match the name. For
example, the hypothetical file name alpha drops whichever of the
following exists: the source schema object named alpha, the class
schema object named alpha, and the resource schema object named
alpha. If the file name begins with the "/" character,
then dropjava prepends ROOT to the schema object name.
If dropjava encounters a file name that does not match a schema object, it displays a message and processes the remaining file names.
The permissible forms of @<database> depend on whether you specify -oci8 or -thin; -oci8 is the default.
Here are some dropjava examples.
dropjava -u scott/tiger -schema TEST ServerObjects.jar
dropjava -thin -u scott/tiger@dbhost:5521:orcl alpha.class beta.props