Tutorial: using Java on MPE/iX

»  Home

» Software
» Papers & Training
» Java
»  Supported JDKs
» OpenSource classlibs
» Documentation
»  PowerPoint
» Cobol pdf
» Tutorial
» Server
» Lars Appel
» Support
» FAQ
» DST


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.

    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.

    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;)
     */
    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.

    Top    Jazz java    Hosted by 3kRanger.com    email 3kRanger    Updated