 |
» |
|
|
 |
 |
 |
Mike Yawn
Hewlett-Packard
Commercial Systems Division
19447 Pruneridge Avenue
Mailstop 47UA
Cupertino, CA 95014
myawn@cup.hp.com
Contents
I. Theoretical Stuff
A. The Java Language
B. The Java Virtual Machine
C. The Java Platform
D. How does Java measure up?
II. Practical Stuff
A. Obtaining Java
B. Installing Java
C. Java Directory Structure
D. Java Components
E. Using Java
F. Where to go for more info
III. Java and Databases
IV. The Java Native Interface
I. Theoretical stuff
In this paper, we'll be looking at Java from a number of perspectives.
Because this is a tutorial, I want to cover some of the nuts-and-bolts
stuff like how to download and install Java, and then how to write,
compile, and execute a simple Java program. However, with Java being
a relatively new technology, I also want to take some time to explain
Java - what it is, what it can do, and why it has received so much
attention in the press. We'll also examine how well it works for
doing typical MPE types of things like accessing databases, as opposed
to typical web-oriented tasks such as animating an HTML page. We'll
cover the theoretical areas first, and save the practical information
for the end.
I-A. The Java language
Every industry publication today is filled with discussion of "Java".
If you've read the various claims for and against Java, you may have
become thoroughly confused by the often conflicting information: is
Java secure? is it portable? is it appropriate for "mission critical"
use?
Part of the confusion stems from the fact that the term "Java" is used
to refer to several distinct parts of a computing platform. In order
to make sense of the claims, you need to understand the various pieces
and how they relate. We'll look in detail at three key components:
The Java programming language, the Java Virtual Machine, and the
Java Platform, or Java APIs. Javascript, which you may have heard of
or seen also, has absolutely nothing whatsoever to do with any component
of Java, and is merely Netscape's attempt to associate their HTML
scripting language with Java.
Sun Microsystems, where Java was developed, used the following bit of
marketing-speak very early on in Java's life to describe the product's
benefits:
Java: A simple, object-oriented, distributed, interpreted, robust,
secure, architecture neutral, portable, high-performance, multithreaded,
and dynamic language.
There is nothing radically new here; each of these attributes can be
applied to one or more languages that were already in existence. But
as computing has evolved, the relative importance of these traits has
changed: mainframe programmers were much more willing to sacrifice
simplicity and portability for performance. Early UNIX implementations
demonstrated the willingness to sacrifice virtually everything for the
sake of an illusion of portability. The emergence of the World Wide Web,
pervasive graphical clients, and advances in software engineering such
as object-oriented programming all set the stage for Java, which strikes
a balance between all these attributes which meets the requirements of
today's distributed computing environments better than any language up
to this point.
If you examine the most popular languages in computing history, you'll
find that each one had some unique niche where it originally flourished.
Languages that never find such a niche are doomed to perish, or become
a curiosity. For those that do find a niche, they either grow beyond
it and become more widely adopted, or they remain tied to it and fade away
when the next wave of computing arrives. Both COBOL are RPG had origins
closely tied to Unit Record equipment. COBOL grew beyond its roots, and
became the most widely used language for business data processing. RPG
code still exists, but its heyday faded with the passing of the keypunch
machine. C gained prominence because of its close ties to the UNIX
operating system; but the extensive use of UNIX in universities virtually
assured the language of a wider use as it became the most widely known
language for new entrants into the IT labor pool. Java first gained
widespread notoriety because of its inclusion of basic internet
functionality - such as URL handling, MIME data types, and Sockets
connections - as part of its original basic API set. Java now appears
well poised to break away from this niche and become the next
widely-adopted language for general purpose computing. The reasons for
this leap will be covered in upcoming sections.
We won't cover each of the claims made for Java above, but a few are
worth a little more attention:
Java is a truly object-oriented language. For those of you who aren't
already believers in the benefits of object-oriented programming styles,
object-oriented code is more maintainable, more reusable, and more modular
than code written in non-object-oriented fashion. C++ is a hybrid,
adding many object-oriented features to C, but not addressing some of
that language's heinous shortcomings.
Java is a simple language to use. Automatic garbage collection means that
users can have the benefits of dynamically created objects, but without
the need to manage memory and worry about proper deallocation. Java
provides references to objects, but does not allow these references to be
used as pointers in numeric expressions or cast to incorrect types.
Java provides numerous sanity-checking features, such as array bounds
checking, to help ensure the correctness of programs.
Java provides an inherent portability missing in other languages, by
leaving virtually nothing as an implementation-defined detail. Word
size and byte order are defined by the language; there are no
#pragma or #ifdef constructs to permit programmers to create or use
non-portable features.
You should understand that the Java language can be implemented
separately from the other Java components. All early implementations
of Java compilers created intermediate code that runs on the Java
Virtual Machine; but some vendors are today producing compilers that
create executable files for a specific architecture.
The Java language continues to evolve. Version 1.0 of the language
provided a very clean, simple, and robust implementation of
object-oriented concepts. In Version 1.1, the most major change was
the introduction of Inner Classes. (see sidebar: Inner Classes and MPE).
Java's designers have indicated that parameterized types will most
likely be added to the language in a future version. On the other
hand, the designers insist they do not plan to add operator overloading,
an often requested feature that Java's designers feel is error prone
and confusing.
Inner Classes and MPE: When Java introduced the Inner Classes feature
in JDK 1.1, it created some problems for the MPE porting effort.
Inner Classes are classes, or objects, that are defined inside of
another object. The makes it easy to place small helper, or 'adapter',
classes in the class they are designed to work with, and is a valuable
extension to the original Java Language Specification. However, the
implementation of Inner Classes specifies that each Inner Class will be
compiled into its own .class file, and that the name of this class file
will be the name of the enclosing class, a '$', and the name of the inner
class. So if class foo defines an inner class bar, the compiler will
place the code for the class in the file foo$bar.class. MPE has never
allowed any special characters as part of file names (standard MPE
allows only upper case letters and numbers; the POSIX extensions to
MPE follow the POSIX .1 standard of also allowing lower case,
underscore, hyphen, and dot).
Because inner classes are a key Java feature, patches have been created
to allow additional characters (essentially, all printable characters)
to be legal for POSIX file names. These patches, MPEJXQ1 and PX2JXQ2,
are site specific patches recommended only for those sites using Java.
We are currently evaluating making this POSIX extension generally
available.
Back to contents
I-B. The Java virtual machine
Most of the attention heaped on Java has not been due to its elegance
as an object-oriented programming language (although many people do
appreciate this aspect of Java), but rather for its use of a Virtual
Machine to provide portability and security.
The Virtual Machine concept is not new. Many compilers, including some
of HP's, produce code that is targeted to an abstract 'virtual machine',
with a second compilation pass converting this virtual machine code into
an architecture-specific executable program. Many of the VM concepts
can also be seen in MPE's object code translation technology for
Compatibility Mode programs. The Java Virtual Machine has implemented
some unique features, however:
The virtual machine was designed specifically to support an
object-oriented language. The ability to resolve overloaded method calls,
a complex operation, is built directly into the instruction set.
The virtual machine provides bytecode verification capabilities to protect
the host system from attack by malicious (or inadvertently harmful)
programs.
The virtual machine provides much better performance than a purely
interpreted language, because the time-consuming tasks of parsing,
checking, and compiling the source code are done before execution.
Most of the operations represented by the virtual machine's instruction
set can then be executed very quickly at run time.
The bytecode verifier is a complex piece of software that is beyond the
scope of this presentation. Briefly, it performs a number of checks on
the generated code to ensure that the instruction set is not being used
in ways that could cause the virtual machine to behave in ways that might
compromise security. (It is not enough for the compiler to enforce these
checks, because a hacker could always alter the bytecodes generated by the
compiler). Because bytecode verification is an expensive operation, the
default behavior is only to verify classes that are loaded from untrusted
applications, such as over the Internet. If preferred, a java command line
option can force verification of all classes (although Java class files
on a local system are no more likely to be harmful than COBOL, C or any
other program files, so using this option is somewhat paranoid).
Back to contents
I-C. The Java platform
Java provides a very robust set of Application Programming Interfaces,
or APIs, that are grouped together in collections called Packages.
It is this part of Java that is evolving most rapidly, and the breadth
and depth of functionality available in these APIs is unprecedented for
a language so young. The true power of Java comes from the availability
of packages to handle an increasing number of complex tasks, leaving
programmers free to concentrate on the application-specific requirements,
rather than having to implement complex infrastructure components to
support the application's needs.
In Part II, we'll look at each of the Java packages at an appropriate
level of detail, so we won't cover many specifics here of what kinds of
APIs are available. Instead, we will focus on how this wide set of APIs
facilitates portability.
If you take a typical MPE program, and ask how difficult it would be to
move it to another platform, you'll usually find that the language is not
the most limiting factor. COBOL, C, FORTRAN, and Pascal programs can
all be moved to other platforms with a minimum of changes. SPL and
Transact programs will be significantly less portable, but then they
never claimed otherwise, so anyone choosing to implement in one of these
languages did not put portability very high on their list of requirements.
What features other than languages impair program portability? On MPE,
it's typically VPLUS, TurboIMAGE, and MPE Intrinsics. Each one of these
is an API to provide access to an MPE-specific implementation.
Proprietary APIs are used to access proprietary services. In the mainframe
and early minicomputer eras, every system was designed this way, and
systems would differentiate themselves by the power, performance, and
flexibility of these APIs. Many of you may have selected an HP 3000
based on the capabilities provided by the combination of TurboIMAGE,
VPLUS, and MPE; in many ways it is still unsurpassed in the strength
of its proprietary interfaces.
Then UNIX came along, and changed the rules of the game forever.
UNIX offered a far weaker feature set, but the promise of easy portability
between systems. Many IT managers found the trade-off worthwhile. And
as more and more companies adopted UNIX, the UNIX vendors poured more
money into evolving the systems to provide the same rich commercial
features as the proprietary platforms. Meanwhile, the proprietary
platforms such as MPE realized that the demand for portability must
be addressed, and open systems APIs such as POSIX have been added to
all the proprietary OSes that survive today.
So pretend for a moment you're on the Java design team, and you have
developed this language and virtual machine that you want to become
the pervasive computing platform of the next wave of computing. What
set of APIs do you build your product on? On the one hand, you have
the Windows APIs - representing the largest share of the market, and
growing, but not today a real factor in the enterprise systems market.
Perhaps a good choice for some companies, but if your paycheck comes
from Scott McNealy, this is not going to be a viable option. Another
choice is the UNIX APIs. But despite years of standardization attempts,
there is no API set you can select that is both sufficiently pervasive
and sufficiently powerful to permit the development of the complex,
distributed applications you think Java is capable of. The only
alternative, you come to realize, is to implement the APIs you need in
Java - in essence, do not target Windows platforms, or UNIX platforms,
but create a Java platform that can be implemented on top of virtually
any operating system. Programs written in the Java language and running
in the Java virtual machine are portable largely because this Java
Platform is sufficiently robust to keep developers from using any other
APIs that would lock them into a single OS platform.
The "100% Pure Java" wars, with Sun and Microsoft as the primary
combatants, reveal just what is at stake here. If 100% Pure Java
becomes the norm, then every Java developer will in effect be developing
software for the HP 3000, along with every other system that implements
the Java Platform (language, VM, and APIs). There could be a resulting
flood of new applications greater than any we have seen in MPE's history.
The term "legacy system" will no longer apply to entire operating systems,
but merely to specific applications which no longer meet your needs.
On the other hand, if Microsoft wins, then they will have succeeded in
fragmenting the Java marketplace just as the UNIX marketplace was
fragmented by various incompatible flavors of UNIX. There will be
some winners - Microsoft among them, and some losers - including MPE.
Also losing will be any company that wants a healthy competition in the
operating system and hardware marketplaces.
I am a strong advocate of the "100% Pure Java" initiative, and at the
same time, I've been working to develop a TurboIMAGE class library that
makes use of the non-portable Java Native Interface. I don't think this
is inconsistent; TurboIMAGE is obviously an MPE-specific technology.
Writing a TurboIMAGE class library that can be ported to other platforms
provides no benefit unless TurboIMAGE itself is ported to those platforms.
However, there are portable database interfaces available - most notably,
the Java Database Connectivity, or JDBC, package from JavaSoft.
Implementing a JDBC interface for TurboIMAGE would provide a portable
interface to TurboIMAGE databases. Programs written on the HP 3000 that
use JDBC to access TurboIMAGE can be ported to other platforms, and use
the same JDBC interfaces to access Oracle, Informix, or whatever other
databases are present on that platform. By the same token, all the
applications being written on other platforms that use JDBC to access
the various relational database engines can be ported to the HP 3000,
and be used without modification to access TurboIMAGE databases.
Given this, if I were an application developer and could support only
one database interface, I would pick JDBC without question. A better
solution might be to support multiple interfaces - JDBC for portability,
direct TurboIMAGE access for the best performance on MPE/iX. Is this
worth the additional effort? Without either one of these technologies
available for performance testing, it's impossible to say. If I were
designing an application today, I would definitely layer my software so
that database access was isolated, making it easy at some future point
to change to a different database access technology. (I would also do
the same with any User Interface code, as the AWT has been the most
volatile of the APIs, and is likely to change again in future releases).
Back to contents
I-D. So how does 'Java' measure up to the claims?
Let's go back to some of Sun's claims for Java and see if they hold up:
I-D-1. Java performance
Sun claims that Java is a "high-performance" language. This raises the
question "compared to what?". When compared to interpreted scripting
languages such as Perl, awk, Transact, Quiz, or the various UNIX shells,
Java provides considerably higher performance. Compared to compiled
languages such as COBOL or C, Java running purely interpreted in a
Virtual Machine can be as much as 10 times slower.
For typical OLTP applications, where much of the execution time is
consumed by database API's or other functions not provided by the
application programmer, the application may not be very sensitive to
the performance of the language used. Only if a significant amount of
time is spent executing the user-written code will the implementation
language make a noticeable impact.
There are a number of techniques for improving Java performance. A
native compiler that produces object code directly for the target
platform should be able to produce Java program files just as fast as
any other natively compiled language, but at the cost of loss of
portability. An interesting compromise is provided through a technique
known as just-in-time compilation. With a just-in-time compiler, the
javac compiler still produces bytecodes for the Java virtual machine,
but these bytecodes are then converted to native instructions at run-time
on a method-by-method basis as each method is called. HP's just-in-time
compiler provides a fourteenfold improvement over the interpreted Java
Virtual Machine when running the popular CaffeineMark benchmark tests.
The just-in-time compiler is a standard part of HP's Java offering for
both MPE/iX and HP-UX.
Sun is also providing improved performance between releases; a number
of performance enhancements were made to the 1.1 release, and even more
are scheduled for the 1.2 version due late this summer.
In short, Java performance stacks up very well against interpreted
languages. Against compiled languages, a Just-in-time compiler can
narrow the performance gap to what would be considered an acceptable
range for most applications. Java performance will continue to improve,
and processing power will continue to become less expensive, so that there
are very few applications for which Java's performance would be considered
unacceptable.
I-D-2. Java security
From the earlier discussions about the differences between the Java
language, virtual machine, and APIs, you should understand that most
claims about Java security are directed at the Virtual Machine.
Much of Java's security is in fact security enforced on Applets. Applets
are Java applications that are intended to run inside of another 'host'
program, which is usually a web browser. Applets are usually transferred
via a network to run on a system other than the one on which they are
stored; in many if not most cases, the system executing the applet does
not want to assume that the site providing the applet is a trusted source.
Therefore, Java imposes a number of restrictions on Applets, such as:
They cannot access the local file system on the system where they are
executed.
They cannot make network connections to any system other than the one
from which they were downloaded.
It is important to note that these restrictions are applied only to
applets; not to applications: if they were applied universally, it
would be impossible to write almost any type of business application
with Java.
Other Java security capabilities include the bytecode verification
technology discussed earlier.
Java's security model seems to be pretty robust. There have been a
few well-publicized holes, which have been fixed, and there could very
well still be vulnerability somewhere. However, given the state of
computer security in general, it does not seem that a computer with Java
on it will be inherently less safe than a computer without Java. With or
without Java, it is only sensible to exercise some degree of caution in
downloading software from completely unknown sources. Also, note that
all Java security flaws have been due to implementation bugs, and not
due to design deficiencies. Contrast this to ActiveX, which has a
fundamentally unsecure design which cannot be corrected through an
improved implementation.
I-D-3. Java portability
So does Java meet the claims of "write once, run anywhere"? Yes,
with certain caveats. First and foremost, this is only true for programs
which are 100% Pure Java. Microsoft's J/Direct and ties between Java and
ActiveX are unmistakable attempts to subvert Java and tie users to
Microsoft-only implementations. Avoid using these features yourself,
and refuse to support vendors who sacrifice portability in favor of these
technologies.
One area where Java has received some criticism is in the AWT look and
feel. Although a particular application may in fact run on a PC, a
UNIX Workstation, and a Macintosh, the implementation of the AWT on
those platforms may cause variations in look and feel. If you talk to
end users, I think you'll find that this is exactly what they want:
the application running on a PC should conform to the standard Windows
application look and feel wherever possible. However, some developers
have expressed disgust over Java's inability to make all these platforms
indistinguishable from one another. Go figure.
Another area where differences may show up between Java implementations
is in the scheduling of threads. The Java specification leaves some
latitude to the developer in how Threads of equal priority are handled.
When thread priorities differ, the highest priority thread must always
run. But if priorities are equal, the runtime may run one thread until
it finishes or blocks, or it may implement some sort of timeslicing
between the equal priority threads. The number of applications that
are dependent on a specific scheduling behavior is very small (and well
written Java programs should not be dependent on this implementation
detail).
In each of these areas - performance, portability, and security -
there is something behind the complaints of the Java-bashers. But
given the alternatives - such as the portability of UNIX software, or
the security of ActiveX -- Java seems to be worth consideration.
Back to contents
II. Practical stuff
In this section we'll provide cookbook-style instructions for obtaining
Java for MPE/iX, installing it, and using it to write, compile, and
execute a simple program.
II-A. Obtaining Java
At the time of this writing, Java is being distributed as freeware
(that is, free of charge and free of support) via a number of channels.
The primary distribution method for Java is
CSY's Jazz web server
As new versions of Java are ported,
they will first become available by being placed on Jazz where they
can be downloaded by any web browser.
Other distribution methods are the
FTP server provided by 3K associates
(look in the POSIX subdirectory) and the
INTEREX freeware tape, compiled by Michael Hensley of
Allegro Consultants and distributed by
the INTEREX User's Group.
Java Versions: The various components that comprise Java are released
as part of a package called the Java Developer's Kit, or JDK. The first
JDK ported to MPE/iX was version 1.0.1, which was released in late 1996.
In the second quarter of 1997, we released JDK 1.1 for MPE/iX to a small
number of beta sites. At the time of this writing (June 97), we have
released a preliminary JDK 1.1.2, and are working on porting the final
JDK 1.1.2. There is also a JDK 1.1.3 currently in beta, and JavaSoft
has announced a late summer availability for JDK 1.2.
Java for MPE/iX requires that you be running MPE/iX Release 5.0, with
patch MPEHX70, or any version of MPE/iX 5.5. Java will also be ready to
run on MPE/iX 6.0 when that OS version is released. If you have any
1.0-based version of Java, it is strongly recommended that you update
to a 1.1-based version; no further bug fixes or enhancements are being
made to the 1.0 releases. You will probably want to obtain and install
patches MPEJXQ1 and PX2JXQ2, as mentioned in the 'Inner Classes and MPE'
box earlier in the paper, to allow you to develop and execute Java code
that uses the inner classes feature of Java.
Back to contents
II-B. Installing Java
Regardless of how you get Java, you will have a choice of two formats:
MOVER format, compatible with MPE/iX 5.0, and MPE/iX 5.5 tar format. The
Java software is identical in both cases; only the packaging methodology
is different.
The 5.5 tarfile or 5.0 mover file needs to be installed on the target
system, using whatever transport method you prefer (MPE :STORE, FTP,
Reflection file transfer, etc.) All files in the archive are stored in
absolute pathname format, so it does not matter where you place the
distribution file before installing. The file must first be unzipped
using the gunzip utility, as shown:
shell/iX> gunzip TARFILE
(Note that if you are using the mover distribution format, the correct
command is gunzip TRUCK ). The .gz extension does not need to be
specified, as the gunzip utility assumes it. (If your transfer process
has deleted the suffix, as the Netscape download tends to do, you can
rename the file with either the MPE :RENAME or shell mv command to add
the suffix back).
After unzipping, Java is installed by either:
shell/iX> tar -xovf TARFILE
or
shell/iX> mover -x TRUCK
If you received Java on the INTEREX FREEWARE tape, an INSTALL script is
included which will do the unzip and install for you.
Shell or CI?
Java can be run either from the MPE Command Interpreter or from the
POSIX shell. There are a few differences between the two environments:
The MPE Command Interpreter will launch Java programs faster, due to
the efficiency of MPE's CREATEPROCESS mechanism compared to POSIX fork()
and exec().
The POSIX shell provides intelligent default values for several
environment variables, so the user does not have to provide values
in most cases.
There are five environment variables which can be used by Java, and you
can make Java easier to use by providing values for these via a command
file or UDC (if you use Java from the MPE CI) or a shell script or
.profile (if you use Java from the POSIX shell). These variables and
their typical settings are:
export SYSNAME=hp3000
This variable is tested by some of the shell scripts provided with Java.
It does not need to be set in the MPE CI environment, since the Java shell
scripts are not used when running from the CI.
export PATH=$PATH:/usr/local/java/latest/bin
setenv HPPATH "!hppath,/usr/local/java/latest/lib/PA-RISC/green_threads"
These variables are not Java-specific, but rather the standard path
variables that are used to search for executable program files. The
Java executable program files are in the directory shown for the HPPATH
variable. Within the shell, we do not execute the Java program files
directly, but instead execute shell scripts shown that are in the
directory indicated by the PATH statement above. These shell scripts
set standard env variables for us (such as CLASSPATH and LD_LIBRARY_PATH
shown below), so that we don't need to specify values for these unless
we wish to add to or replace the standard settings.
export CLASSPATH=$CLASSPATH:(add your stuff here)
setenv CLASSPATH "/usr/local/java/latest/lib/classes.zip:(add your stuff here)"
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:(add your stuff here)
setenv LD_LIBRARY_PATH "/usr/local/java/latest/lib/PA-RISC/green_threads:
(add your stuff here)"
export THREADS_FLAG=green
export DISPLAY=sysname:0.0
setenv DISPLAY "sysname:0.0"
The DISPLAY value is used by the AWT and Applet classes to locate the display
device. Only X-Windows compatible display devices (UNIX workstations,
X-terminals, or PCs running X-Windows emulation software) are supported
for the display device. Most HP 3000 Java users probably won't need
the AWT on the HP 3000; it is more typical to have user interface code
downloaded to a web browser, or run in some other client/server type of
configuration. We certainly recommend this for your own development:
design the user interface as a separable module that can be executed
on a client, and leave application logic and database access modules on
the server. However, you may encounter Java applications that aren't
designed this way, and the MPE AWT implementation will allow you to
execute these applications, if you can provide an X-Windows capable
display device accessible from the HP 3000.
Back to contents
II-C. Java directory structure
Java is installed in MPE's hierarchical file system under the path
/usr/local/java. There are several additional directory levels
beyond this point.
The next level down specifies the Java version. For example, version
1.1.2 of Java is installed under /usr/local/java/jdk1.1.2. We recommend
that you create a symbolic link called 'latest' that can be used to access
the most recent version of Java, so that shell scripts, jobstreams, and
command files do not need to be changed every time a new version of Java
is installed. This can be done as:
shell/iX> ln -s /usr/local/java/jdk1.1.2 /usr/local/java/latest
or
:NEWLINK /usr/local/java/latest, /usr/local/java/jdk1.1.2
When new versions are installed, this link can be removed and a new
link created. If you have software that must be run with a particular
version of Java, they can always specify a specific version directory
rather than 'latest'.
Under /usr/local/java/latest are two major hierarchies: lib and bin;
the optional hierarchies demo and doc, and a number of files, such as
the latest README file.
The bin hierarchy contains Java program files, and shell scripts used to
run those programs. Under /usr/local/java/latest/bin are shell scripts
used to run each of the Java components (which will be described in the
following section). So for example, /usr/local/java/latest/java is the
script to run the latest version of the Java interpreter. If the PATH
(or HPPATH) variable is correctly set, is not necessary to specify this
entire path; 'java MyClass' would be sufficient.
The actual program binaries are two levels further down in the hierarchy.
Under /usr/local/java/latest/bin is the directory PA-RISC. If MPE were
ever ported to a hardware architecture other than PA-RISC, additional
directories could be created at this level to hold the platform-specific
binaries. Under the PA-RISC directory is the directory green_threads.
This directory holds the actual Java programs, Green threads is a
simulated threads library provided by JavaSoft. If we choose at some
point to create a version of Java that uses MPE's kernel threads, a
native_threads subdirectory would be created at this level to hold that
version of the binaries.
The lib hierarchy follows the same structure as the bin hierarchy, with
PA-RISCC and green_threads subdirectories. There is one file that resides
at the top level of the lib hierarchy: classes.zip. This is an archive
file containing all of the standard Java classes. It does not need to be
unzipped to be accessed (and in fact, can be accessed faster as a single
zip file than as hundreds of individual disk files). At the bottom level
of the hierarchy are a number of specialized libraries that are dynamically
loaded when needed for certain Java tasks; for example, libnet.sl contains
the Java networking code, and libawt.sl contains code used by the Abstract
Windowing Toolkit.
The demo directory holds a number of demo programs.
The doc directory holds HTML format API documentation.
Back to contents
II-D. Java components
We'll take some time now to examine what's included in the Java
distribution. If you have experience with Java on any other platform,
this information should be a review; there are no added or deleted
components in MPE's Java implementation as compared to the Solaris or
Windows implementations, which are the reference implementations which
all others should emulate to the greatest extent possible.
II-D-1. Programs
There are fewer program files in the Java distribution that you would
probably expect, primarily because many Java functions are provided
by Java classes, rather than MPE binary files. The only binaries are:
java: The optimized version of the Java interpreter
java_g The debugging version of the Java interpreter
javah - The Java header file generator
javap - The Java class file disassember
II-D-2. Shell scripts
A single Java shell script, called .java_wrapper, is used to access
most Java binaries. This script sets standard values for the
CLASSPATH and LD_LIBRARY_PATH variables, checks whether the
green_threads or native_threads executables should be used
(only green_threads are currently supported on MPE), and invokes the
Java virtual machine for the specified class.
Several Java programs and utilities are really just classes that get
executed by the Java Virtual Machine. For example, each of the
following 'programs' can actually be run by passing the name of the
appropriate class to Java:
To run You can type Or:
javac javac foo.java java sun.tools.javac.Main foo.java
appletviewer appletviewer foo.html java sun.applet.AppletViewer foo.html
javadoc javadoc foo.class java sun.tools.javadoc.Main foo.class
The Java utilities that are run via shell scripts include:
appletviewer - this utility can act as a stand-in for a web browser to
allow testing of Applets. It is especially useful if your HP 3000
is not a web server, but you want to develop and test Java applets
on the HP 3000.
jar - The Java ARchive tool. Like the UNIX tar utility, this tool
can be used to combine a number of files together into a single
compressed file (also like PKZIP on the PC side). Using jar files
can significantly reduce the download time of applets that include
multiple class files.
javac - The Java bytecode compiler.
javadoc - The Java documentation generator. Takes special format
comments out of Java source files and can be used to produce HTML
format documentation.
javakey - used to perform a number of tasks related to key generation
and digital signing.
jdb - the Java debugger.
native2ascii - if Java programs are written in foreign locales with
non-ASCII character sets, the source must be passed through this
utility before it can be compiled by the javac compiler.
serialver - Produces a unique serial version ID which can be used by
the object serialization APIs to properly handle object versioning.
II-D-3. Classes
As we've stated early, much of Java's portability comes from its class
libraries, which are called packages in Java. The original 1.0 release
of Java included 8 packages; in the 1.1 release, there were 23 packages.
Looking at the packages that have been added gives us a glance at the
powerful potential of Java, and also some clues as to its direction.
JDK 1.0 Classes. Of the original 8 packages, three of them - java.lang,
java.io, and java.util - are considered the 'core classes', without which
Java the language couldn't function. The java.lang classes include basic
data types such as Boolean, Character, Integer, and String; the
fundamental building blocks of the object-oriented features of Java,
such as Object and Class; and the core components of the Java runtime
environment, such as Process and Thread. The java.io package contains
classes to deal with file and terminal I/O. The java.util package includes
some general-purpose utility classes, such as Date and Random, plus a
number of classes used by the javac compiler, but also useful for a
number of end-user tasks, such as Stack, Vector, Hashtable, Enumeration,
and BitSet.
The remaining five classes - java.applet, java.awt, java.awt.image,
java.awt.peer, and java.net - are all heavily involved in producing
graphical content that can be downloaded over the internet to a web
browser. From the functionality in these packages, the original target
audience for Java is unmistakable, and it is easy to see why Java quickly
became the dominant language for web page designers.
JDK 1.1 Classes. In JDK 1.1, we see Java continue to add functionality
of interest to web page designers, but we also see Java's designers
pushing the language toward more general-purpose distributed computing
usage.
The Abstract Windowing Toolkit is extended with the java.awt.datatransfer
class, which implements clipboard-based cut & paste functionality in 1.1,
and is expected to include drag-and-drop support in a future release;
and also with the java.awt.event package, which implements a new Event
model that is more scaleable to large-scale applications than the 1.0
implementation.
A new extension to the Java platform, first introduced as a separate
add-on to JDK 1.0 and now included with JDK 1.1, is JavaBeans. JavaBeans
are reusable software components that are designed to be graphically
manipulated by application builder tools. Current JavaBeans are usually
GUI components or other very simple components, but an Enterprise JavaBeans
specification for more complex components is currently under review,
and Enterprise JavaBeans should be part of the next major JDK release.
The Reflection API, implemented in the java.lang.reflect package, provides
support for JavaBeans customization capabilities and for any other tools
which manipulate Java objects. The Reflection API allows you to retrieve
information about a class, in a manner similar to DBINFO calls for
retrieving information about IMAGE databases. The Reflection API
defines Java Classes to represent Fields, Method, and Constructor types.
In addition, the standard Java Class type has been extended with new
methods that will allow you to query a class and get back these new Field,
Method, and Constructor types describing the class of interest. (Because
all Java classes are subclasses of the Class type, this means you can use
these new functions on any Java class).
Java's Remote Method Invocation (RMI) capability is new in JDK 1.1,
and provides the infrastructure necessary to support distributed objects.
The classes that implement RMI are in the java.rmi, java.rmi.dgc,
java.rmi.registry, and java.rmi.server packages.
Java security was enhanced in JDK 1.1 to support signed applets, key
pair management, and cryptographic functions. The classes required to
support these security features are in the java.security, java.security.acl,
java.security.interfaces, and java.math packages.
The java.sql package implements the JDBC database connectivity API.
While the java.sql package is available as part of MPE's JDK 1.1.2, the
package has not been extended to include any knowledge of any MPE
databases, and is thus not usable at present. (If JDBC is important to
you, please work with SIG JAVA to get this functionality properly
prioritized).
The java.text packages provides internationalization support, including
collating sequences; date, time, and currency formats, and other
capabilities needed to support various locales.
The java.util.zip package provides compression capabilities used by the
Java ARchive tool, or JAR.
JDK 1.2 Speculation. The content of JDK 1.2 is still being determined,
but a number of new APIs have been announced via the JavaSoft web site.
These include the following:
Building on the current foundation: The AWT will be extended with Java
Foundation Classes (JFC), a new set of GUI objects such as tabbed folders,
font and color pickers, tool tips, and the like that facilitate more
rapid development of user interfaces. The Java 2D API will provide more
flexible text-rendering capabilities, in place of the current limited
font selection. The Java Media API goes even further, providing 3D
animation, graphics, advanced sound, and speech capabilities. The Java
Server API adds 'servlet' capabilities that can be implemented in a
web server.
More for the Enterprise user: Java IDL will provide CORBA
interoperability, and JNDI is the Java Naming and Directory Interfaces.
The Java Commerce API provides the services needed to support financial
transactions on the web. The Java Management API provides a foundation
for building distributed system and network management tools in Java.
Going after vertical markets: Java has announced industry forums to
promote Java use in specific industries. JFOX is targeted at the
financial services industry, and JTone at the telecom industry.
Expect to see industry-specific APIs emerge from these efforts,
and additional industries will no doubt be targeted in the future.
II-D-4. Libraries
Most of Java itself is written in Java, and the hundreds of Java class
files that make up the JDK are distributed in a single zipped file called
classes.zip. Some portions, however, have been implemented in C, and the
C code is distributed in a number of XL files. For each library listed
below, there are actually two libraries: the library named is the optimized
version of the library. The same library name, with a _g extension prior
to the .sl, is the debugging version of the same library. Java will
automatically select the right library to load based on whether you use
the optimized (java) or debugging (java_g) version of the Java interpreter.
libJdbcOdbc.sl - this library implements the C portions of JDBC
libagent.sl - this library provides support for the debugger
libawt.sl - this library includes the Motif interfaces needed to implement
the AWT
libjava.sl - this library includes C code used by the Java runtime
libjpeg.sl - this library includes code to handle JPEG format images
libmath.sl - this library implements math functions required for
cryptography and the java.math package
libmmedia.sl - this library serves no purpose on MPE currently; it provides
interfaces to an audio driver, if one is present.
libnet.sl - this library implements networking functionality
libsysresource.sl - protocol to support resource (e.g., jpeg, audio)
files in zipped JAR
libtawt.sl - this library implements the 'Tiny AWT', or lightweight AWT
components
libzip.sl - this library is used by the java.zip file compression APIs
javaxl.pub.sys - this MPE-specific library includes the priv mode code
necessary to handle dynamic code page allocation and initialization for
the just-in-time compiler.
Back to contents
II-E. Using Java
II-E-1. Writing Java programs
There are no unique tools on the HP 3000 for writing Java programs;
you just select your favorite word processor and enter the program text.
You can use either a traditional HP 3000 editor such as EDIT/3000 or HP
EDIT, or you can use the vi editor from within the POSIX shell.
The naming of a Java source file should follow the following conventions:
The name must be followed the extension ".java"
The name is case-sensitive. While not a requirement, it is conventional to
use mixed case in class names, with an initial capital and additional
capitals used if the class name contains more than one word (e.g.,
HelloWorld.class).
Because of these requirements, if you use an editor which does not support
full POSIX naming conventions, you must either use file equations or
rename your source file to meet the requirements.
If your program is part of a package, it needs to be placed in an HFS
directory whose name is the same as the package name.
For an example, consider the following, perhaps the simplest possible
Java program:
public class HelloWorld
{
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
Because the class name is HelloWorld, this program needs to be saved as
HelloWorld.java.
II-E-2. Compiling a program
The compiler for Java programs is called javac, so the above program is
compiled simply by:
javac HelloWorld.java
This command can be entered at either a CI prompt or at a shell prompt.
The compiler will produce a class file called HelloWorld.class.
II-E-3. Executing a program
To run the above program, you simply type:
java HelloWorld
at either the CI or shell prompt. Note that the .class extension isn't
needed (and will cause an error if specified).
II-E-4. Hey, what about that just-in-time compiler?
We talked earlier about the just-in-time compiler, so you're probably
wondering what you need to do to run it. The answer is: nothing; you
just did. When you typed 'java HelloWorld' above, the just-in-time
compiler was invoked to compile the class and execute it. You will always
get the benefit of the just-in-time compiler unless you specifically disable
it by specifying the -nojit option on the java command line.
II-E-5. Cross-platform Java development
Using an MPE editor and the command-line interfaces shown above will be
familiar to MPE programmers, but will at the same time seem rather
antiquated to anyone who has worked with some of the Java Integrated
Development Environments available, such as Symantec Cafe. So is there
an IDE available for MPE programmers?
Because of Java's unique portability, any Java IDE can be used to generate
code targeted for the MPE platform. You could enter and compile the
above program into your favorite IDE, and then move the resulting .class
file to an MPE (or any other Java-compatible) system. The class file can
then be executed, including compilation by the just-in-time compiler, with
no additional steps required.
Using Samba, you can even have your Windows-based development system
automatically store Java source and/or class files directly on your
HP 3000, removing the need to transfer files in a separate step.
These capabilities seem to minimize the need for an Integrated Development
Environment that actually runs on the MPE platform; however, Sun's Java
Workshop development environment has been licensed for MPE, although we
have not yet looked at the porting effort involved. If SIG JAVA were to
rank this item highly, we would undertake an investigation on the port.
II-F. Where to go for more info
If you want to pick up a book to learn Java, finding one won't be a problem.
There are so many Java books currently on the market that the problem will
be picking a good one out of the many rushed-to-market efforts vying for
your attention. I've only examined a few of these in any detail. For an
introductory book on Java, I find Java in a Nutshell, now available in a
second edition covering JDK 1.1, to be an excellent work. Many Java
users have recommended Teach Yourself Java in 21 days as another good starting
point. Also highly recommended is Thinking in Java, scheduled for
publication in September, but downloadable today over the web
from this link.
If you're interested in new features in JDK 1.1, you should be cautioned
that many books that claim to cover 1.1 features were in fact published
before 1.1 was available, and are based on preliminary information.
These books may provide a satisfactory overview, but lack the code
examples and caveats that can only come from actually using JDK1.1.
For more advanced topics, you'll have no problems finding books focused
on the AWT, JavaBeans, JDBC, or just about any other Java topic. The
books published by O'Reilly and Associates, the JavaSoft Press series
published by Prentice-Hall, and the official specification books (The
Java Language Specification, the Java Virtual Machine Specification, and
the Java API Specification [2 volumes] published by Addison-Wesley all
are frequently recommended on the Internet by Java users. Your best bet
is to ask others, in a forum such as USENET or SIG JAVA, for
recommendations, or just be prepared to spend some time browsing at the
bookstore before making your selection.
Resources on the World Wide Web: A search for 'Java' in your web
browser will find more hits than you could possibly read in your lifetime.
The following two URLs are good starting points:
The Official JavaSoft home page is updated
very frequently. Check here for new releases of add-on products, such as
the Beans Development Kit (BDK), Java Workshop, or Java Web Server.
Online tutorials and reference documents are available, plus access to
developer resources and a wealth of other information. Worth visiting
often.
The Home Page for
Java on the HP 3000. contains the latest MPE-specific Java
information, and downloadable software.
SIG JAVA is the Interex Special Interest Group for Java on all HP
Platforms. SIG JAVA holds discussions via the SIGJAVA-L mailing list.
You can subscribe by sending an email to listserv@interex.org with the
message 'subscribe sigjava-L yourname' in the body of the message.
You can then send email to the entire mailing list by addressing a
message to sigjava-l@interex.org.
The comp.lang.java.* newsgroups are very active with discussion of all
aspects of Java. While there is lots of useful information here, the
volume is so high that regular reading of these groups is quite
time-consuming.
MPE-specific Java issues will also be discussed on the comp.sys.hp.mpe
USENET newsgroup, or its mirrored mailing list, HP3000-L. The 3000
News Wire also provides extensive coverage of any Java related
HP 3000 developments.
Back to contents
III. Java and databases
If Java is to be used as a general purpose computing language,
especially in enterprise roles, then database access will be a key
requirement. The original JDK 1.0 version of Java made no provision
for database access, short of allowing native method calls to be used
to access any platform or database-specific APIs.
JDBC
After JDK 1.0, JavaSoft introduced the JDBC, or Java DataBase
Connectivity, standard, and the java.sql package that implements the
standard. JDBC was then included as part of the JDK 1.1 release.
The JDBC interface is modeled after the widely used ODBC standard.
J/SQL
A competing standard is the J/SQL standard. Unlike JDBC, which provides
an API interface, J/SQL permits embedded SQL within Java programs, just
as is done today with COBOL or other languages. A preprocessor is then
used to convert the embedded SQL to API calls.
ADBC
ADBC, for Adager DataBase Connectivity, is a client-side Java interface
to TurboIMAGE databases. Java clients use the JDBC API, which communicates
with a server process running on the HP 3000 which then handles interaction
with the TurboIMAGE database.
TurboIMAGE class library for Java and C++
Another possibility for access to TurboIMAGE databases is the TurboIMAGE
package that currently exists in prototype form.
This package is written in Java and currently supports only a limited
number of TurboIMAGE calls, but work continues on adding more features
to the package. The complete package, including documentation, is
available for download from CSY's Jazz web server. We'll use this
package as an example in the following section on the Java Native
Interface.
Currently, a Java implementation of the class library is being worked
on. Also planned is a C++ version, so that there will be a common API
across all object-oriented languages available for the HP 3000.
Back to contents
IV. The Java native interface (JNI)
The Java Native Interface provides interfaces for calling between Java
and C. If interoperability with another language is required, C stubs
can be written as an intermediate layer.
Any Java program which uses the JNI is not 100% Pure Java, and will not
be portable to other platforms. Therefore, the JNI should be a last
resort when the desired functionality cannot be implemented in Java, or
used as a bridge between new Java code and legacy code written in another
language.
We will be using as an example a fragment of code from the still-under
development TurboIMAGE class library. The example we will take is DBOPEN.
Step 1: include a native method declaration in the Java class
When you realize you have a function that needs to be implemented in
another language, you encapsulate that function as a method call. In a
case such as this where we are interfacing to existing code, there is
probably already a specific interface (such as an intrinsic) that is the
target. However, the JNI naming and parameter requirements are such that
you cannot call the target directly. You can, however, use a function
with the same name, and even the same parameters, as the target. That is
what we will do in this case: create a native method called DBOPEN which
looks very much like the DBOPEN intrinsic.
private native void DBOPEN(byte base[], String pass,
short mode, DBStatus status);
We declare this function 'private' because it is only called within the
Database class (by our open() method). We've already covered native;
void is the return type (there is no return value). We pass four
parameters. Base is an array of bytes, because a string type causes
problems if the DBOPEN base id, which it will place in the first two
bytes, contains a zero in either byte. The password is a string; mode
is a 16-bit value. DBStatus could be passed as an array of short values,
but we've created an Object for it so that we can provide methods to
return the various elements in a meaningful way (e.g., getStatus,
getNextRecordPointer, getSynonymChainLength).
Step 2: include a static call to load the XL which contains the C code.
When we've completed our C code that implements the native function,
we'll add it to an XL. By Java naming convention, this XL will be a
POSIX-named file consisting of the prefix 'lib', a user specified library
name, and the extension '.sl' (for Shared Library). Since this library
will hold all the functions of the TurboIMAGE package, we'll name it
libTurboIMAGE.sl. Our Database class needs to load this library. We only
want the load to happen once, so we make it a static code block (otherwise,
it would get loaded for each Database object we created). The call to
load the library is called loadlibrary, and it is a static method of class
System. So the code we need to add looks like this:
static {
System.loadLibrary("TurboIMAGE");
}
So here's the Java code for Database.java:
package TurboIMAGE;
/** This class is used to represent a TurboIMAGE database.
*
* @version X.00.10, for JDK 1.1, April 1997
* @author Mike Yawn
*/
public class Database {
// Intrinsic Parameters
byte[] basename = new byte[26];
String password = new String(";");
String dummy = new String(" "); // an ignored parameter
DBStatus status = new DBStatus();
static {
// Note actual library name is libTurboIMAGE[_g].sl
System.loadLibrary("TurboIMAGE");
}
/** Constructor to create database object, given a
* local database root file name. If the first two
* characters you pass are not blanks, this routine
* will add blanks to the beginning of the name. If
* the last character is not a semicolon, this routine
* will add one. Filename should be in MPE syntax.
* @param dbRootFile The name of the database root file.
*/
public Database(String dbRootFile){
int endchar = dbRootFile.length();
if (dbRootFile.startsWith(" ")){
basename = dbRootFile.getBytes();
} else {
basename[0] = ' '; basename[1] = ' ';
for (int i=0; i<endchar; i++) {
basename[i+2] = (byte) dbRootFile.charAt(i);
}
endchar += 2;
}
if((basename[endchar-1] != ';') && (basename[endchar-1] != ' ')) {
basename[endchar]= ';';
}
}
/** Set the database password. Will add trailing semicolon
* if not specified by the user. If this method is not
* called prior to an open call, the creator password will
* be used as a default */
public void setPassword(String pass){
if(pass.endsWith(";")) {
password = new String(pass);
} else {
password = new String(pass + ";");
}
}
/** Open the database with explicit mode.
* Numeric mode parameters will be more familiar to long-time
* users of the TurboIMAGE intrinsic calls. Additional calls
* are available that use mnemonics to describe the open mode,
* which is more self-documenting.
*
* @param mode 16-bit numeric value for open mode
*/
public void open(short mode) throws IMAGEException {
DBOPEN(basename, password, mode, status);
}
// Stubs that call TurboIMAGE Intrinsics
private native void DBOPEN(byte base[], String pass, short mode,
DBStatus status);
// main method allows this class to be tested independently. In actual
// usage, this class' main method is never executed.
public static void main(String[] argv) {
Database testdb;
String testname;
String testpass;
Byte modein;
Short testmode;
java.io.DataInputStream ins = new java.io.DataInputStream(System.in);
try {
System.out.print("Enter database name :");
testname = ins.readLine();
System.out.print("Enter password :");
testpass = ins.readLine();;
System.out.print("Enter mode :");
testmode = new Short(ins.readLine());
// above may throw NumberFormatException
testdb = new Database(testname);
testdb.setPassword(testpass);
testdb.open(testmode.shortValue());
System.out.println("now open: " + testname);
} catch (Exception e) {
System.out.println("Database main: " + e);
}
}
}
The preceding code shows our current version of Database.java.
Note the following things in the code:
This class belongs to a package called TurboIMAGE. Other classes in the
package include DBStatus and IMAGEException. There are also classes,
which we will not be looking at, called Dataset, Entry, and ItemDescription.
Java package names must reflect the directory where the classes reside,
so all our Java code is being kept in a directory called TurboIMAGE.
In our case, the full path is /JAVA/DEMO/TurboIMAGE; the /JAVA/DEMO isn't
part of the package name, but must be added to our CLASSPATH variable.
/JAVA/DEMO/TurboIMAGE will need to be added to our LD_LIBRARY_PATH
variable.
The class has attributes to hold the basename, password, and status.
The loadlibrary call will load the XL containing the C code
(Step 2 above)
The class has a constructor to create a new Database object. Note that we
allow the user to ignore TurboIMAGE requirements for blanks at the
beginning of the database name, and a trailing semicolon or blank; we
take care of this internally. We also add a trailing semicolon on the
password, if omitted.
In the full Database class, we have several different open methods
(such as openSharedModify, openExclusiveModify, etc.) that relieve the
user of needing to know a numeric mode value. However, the open method we
test is the one most familiar to experienced TurboIMAGE users, and specifies
the mode via a numeric value.
The native keyword on the declaration on DBOPEN tells us this function
will be implemented in C (see Step 1).
A neat feature of Java is the ability to put a 'main' method in a class
that isn't normally run by itself, and use that main method as a test for
the class. (This is possible in C as well.) Our main method tests the
DBOPEN interface.
Step 3: compile the class
Simply type 'javac Database.java' to compile the Java class.
Step 4: run javah to create C headers
The program javah is used to create C function prototype definitions
from a Java class. The -jni option is used to specify the new
JDK 1.1 format.
javah -jni TurboIMAGE.Database
Here's the resulting file C language header file,
TurboIMAGE_Database.h:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class TurboIMAGE_Database */
#ifndef _Included_TurboIMAGE_Database
#define _Included_TurboIMAGE_Database
#ifdef __cplusplus
extern "C"
#endif
/*
* Class: TurboIMAGE_Database
* Method: DBOPEN
* Signature: ([BLjava/lang/String;SLTurboIMAGE/DBStatus;)V
*/
JNIEXPORT void JNICALL Java_TurboIMAGE_Database_DBOPEN
(JNIEnv *, jobject, jbyteArray, jstring, jshort, jobject);
#ifdef __cplusplus
}
#endif
#endif
Things to note here:
The signature specifies the parameter types and return type for the
function. You will need to learn this notation (documented in the JNI
reference) to use JNI method calls
The JNIEXPORT and JNICALL declarations are null on MPE; they are provided
by the JNI for Windows use.
Native method function names are assembled as follows: The prefix "Java_",
the package name (if any), underscore, the class name, underscore, and the
method name. For overloaded functions, the name is mangled with the
inclusion of parameter type info (See the JNI specification; I won't
try to explain).
Two parameters have been added to the beginning of the parameter list.
The JNIEnv pointer is used for access to hundreds of JNI functions that
provide access to the Java Virtual Machine. The second parameter is a
pointer to the current object, and can be used to access fields and
methods of the Database class from within this call.
Our four specified parameters have been converted to JNI types whose
implementation may change between architectures, thus again limiting the
portability of JNI code.
Step 5: write the C implementation
I won't go through the demo line-by-line; the basic flow is this: Perform
any necessary conversion between Java data types and C data types, then call
the target function with the C data types. Then convert back to Java data
types anything that needs to have visibility from the Java portion of the
class code. Finally, free any temporary resources we may have allocated
to hold the C representations of the data.
The basename, password, and mode were passed in to us, so there are
relatively simple functions to convert those into proper format.
GetByteArrayElements gives us a pointer to the start of our name array,
and GetStringUTFCharacters converts the Unicode-encoded password String
into an ASCII string suitable for use with MPE intrinsics. (Optionally,
we could have had none of these passed in, and used the JNI functions to
access the class attribute fields).
We were also passed a reference to a DBStatus object; using this is a bit
tricker. The sequence of calls is: GetObjectClass, to change our
generic object reference to a class reference that allows us access to the
class' methods and attributes. GetFieldID gives us a reference to the
halfword field, which we must specify by both name and signature (short
array, or "[S"). This is the actual 10-CMword status array we wish to use.
However, what is returned is just a reference to it; we need to convert
this to a pointer, by passing it to GetObjectField, and finally to the
array itself, by calling GetShortArrayElements.
C Source code for DatabaseImpl.c:
#include "TurboIMAGE.h"
/* function to throw exceptions based on TurboIMAGE errors */
void ThrowException(JNIEnv *env, char * intrinsic, void *CStatus)
{
char message[100];
short msglen;
jclass IEClass;
/* first report & clear any pending exception */
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
/* now see what our problem is */
dberror(CStatus, message, &msglen);
message[msglen] = '\0'; /* needs null terminator */
/* and throw an exception to report it */
IEClass=(*env)->FindClass(env, "TurboIMAGE/IMAGEException");
(*env)->ThrowNew(env, IEClass, message);
}
//**********************************************************
//********** TurboIMAGE Database Implementation ************
//**********************************************************
/* Function to call DBOPEN */
JNIEXPORT void JNICALL
Java_TurboIMAGE_Database_DBOPEN(JNIEnv *env,
jobject this,
jbyteArray j_basename,
jstring j_password,
jshort j_mode,
jobject j_status) {
int i;
// JNI types for accessing DBStatus
jfieldID f_halfword;
jobject p_halfword;
jshort *a_halfword;
jclass c_DBStatus;
// Get JNI fields into C types
jbyte *base = (*env)->GetByteArrayElements(env, j_basename, 0);
const char *pass = (*env)->GetStringUTFChars(env, j_password, 0);
c_DBStatus = (*env)->GetObjectClass(env, j_status);
f_halfword = (*env)->GetFieldID(env, c_DBStatus,
"halfword", "[S");
p_halfword = (*env)->GetObjectField(env, j_status, f_halfword);
a_halfword = (*env)->GetShortArrayElements(env, p_halfword, 0);
dbopen(base, pass, &j_mode, a_halfword);
if (a_halfword[0] < 0){
ThrowException(env, "DBOPEN", a_halfword);
return;
}
(*env)->ReleaseByteArrayElements(env, j_basename, base, 0);
(*env)->ReleaseStringUTFChars(env, j_password, pass);
(*env)->ReleaseShortArrayElements(env, p_halfword, a_halfword, 0);
}
Step 6: compile the C code and place in an XL
I used gcc, although the HP c89 compiler would work as well. The Java
include files needed by the JNI are in the directories shown with the -I
compiler option below. NOTE: This all needs to go on one line
(wraparound OK), and is split below solely for readability.
shell/iX> gcc -I/usr/local/java/latest/include
-I/usr/local/java/latest/include/mpe
-c -o DatabaseImpl.o DatabaseImpl.c
shell/iX> callci linkedit
LinkEdit> buildxl ./libTurboIMAGE.sl;limit=10
LinkEdit> addxl ./DatabaseImpl.o ./libTurboIMAGE.sl
ignore the warning about filecode 0 on DatabaseImpl.o
LinkEdit> exit
Step 7: test the Java class
shell/iX> java Database
As prompted, enter a basename, password, and mode. The Java class will
attempt to open the database. If it succeeds, you'll see nothing; if it
fails, you'll see the an IMAGEException message (the text of which comes
from DBERROR).
And now you're done. The JNI isn't very intuitive, but you should be
able to get the hang of it with enough patience. As of the time this was
written, there were still some bugs in the MPE JNI being worked out; check
for the latest updates on Jazz or through SIG JAVA before investing any
significant time trouble-shooting problems that may not be on your end.
I recommend visiting the JavaSoft web site and examining the JNI tutorial
that is there, and downloading the JNI specification if you're going to be
using the JNI. I have not yet found a book that covers the JNI well,
although I'm sure there are some out there, or will be soon.
|
|
|