Table of Contents

Calling PL/I native methods from Java

  • What is java?
  • The Java Development Kit
  • Java applications and applets
  • Java native methods, what are they and why use them?
  • Why call a native language?
  • Benefits of calling a native language
  • A sample application for all platforms

  • How do you call PL/I from Java?
  • Creating a class with native methods
  • Linking your programs
  • Using a MAKEFILE
  • Writing and compiling your PL/I and Java programs
  • Calling your PL/I native methods
  • Summarizing what you have learned
  • References and Resources

  • Calling PL/I native methods from Java

    This chapter gives an overview of Java and explains why you might be interested in using it with PL/I. Because the actual implementation of calling PL/I from Java is subject to frequent change, these steps are described in a file named plijava.htm shipped with VisualAge PL/I. You need access to a browser to view the information in this file.

    For OS/2, the browsable file is in the d:\ibmpli\help directory and the sample programs are in d:\ibmpli\samples, assuming you used d:\ibmpli\ to install the product.

    For Windows NT, the browsable file is in the d:\ibmpliw\books directory and the sample programs are in d:\ibmpliw\samples, assuming you used d:\ibmpliw\ to install the product.


    What is java?

    Java is an object-oriented programming language invented by Sun Microsystems and provides the most powerful way to make Internet documents interactive. Java was derived from C++, but is much more approachable. Java designers simplified it by removing memory management, pointers, and operator overloading. They also made Java more 'internet aware' by adding classes and methods for networking (TCP/IP, URLs, Sockets) and Applets.

    The Java Development Kit 1.1.8 (most current version of JDK 1.1.x as of the printing of the document) has classes that support the Abstract Window Toolkit (AWT), I/O, utilities, and many other functions.

    The Java compiler does not produce platform dependent machine code. Instead, it produces what are known as java byte codes in a Java .class file. These byte codes are not specific to any one processor or platform.

    Java .class files are executed by an interpreter known as a Java virtual machine. The .class files are machine independent, meaning they can be compiled on one platform and run on any other platform that has a Java virtual machine. This is a great benefit to programmers who want to write a program once and then have it run on many platforms without altering the code.

    Because Java is very new, it is still evolving. Java support on OS/2 first came out at the Java 1.0.2 level. The current support on OS/2 is for Java 1.1.8 which is generally available at the time this information was written. Sun Microsystems provides a Software Development Kit (SDK) that supports Java 1.1.8 on Windows platforms. There are significant changes between JDK 1.0.2 and JDK 1.1.8. You should always start with the newest version of Java available when developing Java applications.

    The Java Development Kit

    The Java Development Kits come with a Java compiler (javac), a Java runtime, debugger and assorted tools. The PL/I sample program provide with VisualAge PL/I was developed using the OS/2 Java 1.1.8 and Sun Microsystems Windows Java Development Kits 1.1.8 and 1.1.6. These Java Development Kits are free.

    Java programs have a suffix of .java. The Java compiler is case sensitive and requires that the source file name matches the class name it contains. For example, the class 'MyFirstJavaClass { }' is different than 'Myfirstjavaclass { }'. The source file for MyFirstJavaClass must be named MyFirstJavaClass.java. The compiler names the output file MyFirstJavaClass.class.

    If you have more than one Java class in your source file, the Java compiler creates a separate .class file for each of the classes it finds.

    Java applications and applets

    A Java program can be either an application or an applet.

    Java applications are self contained programs much like traditional PL/I programs. They contain one or more classes, few or many methods, and run on their own.

    Java applets are designed to run in a browser environment. This makes them a good choice for internet or client/server-based applications. Applets operate with the following restrictions:

    These restrictions are intended to protect your system from a 'misbehaving' applet.

    Applets and applications also differ in their structure. Here are a couple of the more significant differences:

    It is possible to create a Java program that can be run either as an applet or an application as long as it adheres to the applet restrictions.

    You can run a Java application by entering a command like the one shown here:

      java myApplication
    

    The java command invokes the Java virtual machine and passes it the name of your Java program. This command is carried out based on the assumption that a file named myApplication.class exists somewhere on the CLASSPATH. Should you encounter a NoSuchMethodError you may append either '.;' or '.\.;' to the beginning of the CLASSPATH environment variable by using the SET CLASSPATH command.

    You run a Java applet by using one of the following:

    For example, the following command would run your myApplet applet on OS/2 by invoking the java interpreter and running the file myApplet.class.

      javapm myApplet
    

    There are many other issues and more information necessary to create and run Java programs. If you are interested in learning more about programming in Java, you might want to invest in a good Java book or set of online information.


    Java native methods, what are they and why use them?

    Java is a fairly complete programming language, however, there could be situations in which you want to call a program written in another programming language. In Java, you do this with a method call to a native language, known as a native method.

    Why call a native language?

    Here are some possible reasons why you might want to call a native language:

    To be fair, here are some reasons why you might not want to call a native language:

    Benefits of calling a native language

    An important benefit of using a native language is being able to leverage your current PL/I skills and PL/I program base. You can continue to use the highly-trained PL/I programmers in your shop to produce powerful applications as well as reuse your existing code.

    You can develop a Graphical User Interface (GUI) using Java that will run on all of the supported platforms that call your native language. By combining a portable GUI and a set of powerful native methods, you are able to move your application from platform to platform.

    As you spend time learning about Java through the sample application provided, you will learn how to connect your legacy code into the flexible world of the internet. As was mentioned in the introduction to this chapter, the methods used to create this sample application scenario are so dynamic that the steps are provided in an online document so we can provide updates as technology evolves.


    A sample application for all platforms

    Our example is a basic inventory-control program that has a Java-built GUI front end client that calls the workhorse PL/I engine through some native methods.

    To see the sample PL/I program, named winecelr.pli, please refer to "winecelr.pli". The two PL/I procedures in this program, 'GetWine' and 'GetDet', are defined as native methods and are called from the classes defined in the wineSamp.java java program. To see this Java program please refer to "wineSamp.java".

    While this application is quite basic in nature, it illustrates what you need to know to hook a PL/I program to Java.


    How do you call PL/I from Java?

    Java designers have created a scheme which allows you to call your native programming language from Java. Each of the following steps is discussed in detail as you proceed through this information.

    1. Create a class with native method definitions or add them to an existing class.

    2. Write and compile your native language and Java programs.

    3. Link your native program into a native library.

    4. Call your native methods from your Java code.

    Creating a class with native methods

    The wineSamp.java file contains several class definitions, two of which call the PL/I native methods. The wineSamp class calls the GetWine native method and the DetailFrame class calls the GetDet native method. Each of these PL/I native methods gets passed and returns some Java objects. The native object module is linked into a load library named wineCelr.dll. Here is what the complete wineSamp.java file looks like: "wineSamp.java".

    The native methods used in the file are described with 'public static native'. The 'native' descriptor tells Java that the implementation of this method will be found in a native library that will be loaded during the execution of the program.

    The GetWine method passes a Java String Object and a boolean flag and gets a Java String Array Object from PL/I in return. The GetDet method passes a Java String Object and gets a Java Object from PL/I in return. More about these Java objects is presented later in the scenario.

    The native load library for our example, wineCelr.dll, is loaded when the wineSamp class is loaded with the System.loadLibrary(..) call.

    Linking your programs

    It is important to know which linkage convention to use for each platform. Not surprisingly, different linkages are used on OS/2 and on Windows.

    On OS/2, the linkage you will need to use for PL/I programs is SYSTEM. On Windows, the linkage to use is STDCALL. If you want to read more about SYSTEM and STDCALL, refer to the respective Programming Guides for those languages.

    On OS/2, you specify linkage by using a suboption of the DEFAULT compile-time option, for example:

      DFT( LINKAGE( SYSTEM ) )
    

    For the Windows platform, you need to use the STDCALL linkage option. The linkage specification in that case would be as follows:

      DFT( LINKAGE( STDCALL ) )
    

    Each linkage convention 'decorates' the external reference of the procedure a little differently. You need to be aware of these differences when you set up your linking defaults. On Windows for example, Java is expecting to find an external reference that looks like '_Java_wineSamp_GetWine' for the GetWine native method. If your external reference looks like 'Java_wineSamp_GetWine', Java will not find it.

    Thus far, there is a lot of information you need to know just to compile and link your Java and PL/I programs. One way to remember all of these details is to use a MAKEFILE.

    Using a MAKEFILE

    A MAKEFILE uses the NMAKE tool which is available on many programming platforms and generally follows these steps:

    1. First, you create a file named yourFile.mak where yourFile is a name you choose.

    2. Next, you insert your make rules, compile commands, and link commands into the special NMAKE syntax.

    3. Finally, you invoke the makefile which performs the compile and link commands that are necessary.

    On both OS/2 and Windows, you invoke your MAKEFILE the same way:

      nmake /f yourFile.mak
    

    If you are interested in makefile details, here are the makefiles for "OS/2". and for "Windows"

    With a basic understanding of the development environment, you can start writing the programs that actually do the work.

    Writing and compiling your PL/I and Java programs

    The sample PL/I program consists of two procedures. The first procedure, GetWine, is called and passed a reference to a Java String Object and a boolean flag. This procedure converts the Java String Object to a PL/I character string and evaluates it. Then GetWine builds an answer set, creates a Java String Array Object to contain it, then returns the Java String Array Object to the calling Java program. In addition, GetWine checks the boolean flag that it is passed and, if True, displays some debugging information during the execution of the program.

    The second procedure is also passed a Java String Object. The operation for GetDet is very similar to that for GetWine. GetDet converts and evaluates the passed string, builds an answer set, creates a different kind of Java Object to contain it, and returns the Java Object to the calling Java program.

    Although the sample PL/I program is quite basic, you should pay attention to the following:

    PL/I compile-time options

    The significant compile-time options used include the following:

    LINKAGE

    For OS/2, DFT( LINKAGE( SYSTEM ) )

    For Windows, DFT( LINKAGE( STDCALL ) )

    BYVALUE

    All variables in Java are passed by reference, not by address.

    XINFO(DEF)

    Generates a wineCelr.def file that contains the exported PL/I routines.

    LANGLVL( SAA2 )

    The compiler accepts the PL/I language definition contained in the VisualAge PL/I Language Reference (OS/2 and Windows).

    LIMITS( EXTNAME( 31 ) )

    Use of this option allows longer external names.

    MARGINS( 1, 100 )

    Extending the margins gives you more room for longer OO-style names.

    MACRO

    Allows you to use the PL/I macro facility for conditional compilations.

    DLLINIT

    Includes the initilization code needed for creating a DLL

    Getting the Procedure statement right

    The sample application is written as a PL/I package and exports two procedures. The external references of these procedures must adhere to the Java native method naming convention, which consists of three parts. The first part identifies the routine to the Java environment, the second part is the name of the Java class that defined the native method, and the third part is the name of the native method itself.

    For example, the external reference for the PL/I subroutine "GetWine" is declared as "_Java_wineSamp_GetWine". Here is a breakdown of the parts of the external reference:

    _Java
    All native methods resident in dynamic libraries must begin with "_Java". The "_" is added to comply with the STDCALL interface

    _wineSamp
    The name of the class where the native method is defined

    _GetWine
    The name of the PL/I subroutine within the PL/I package that is called by the native method

    There is a difference between coding a native method in PL/I and in C. The javah tool, which is shipped with the JDK, assures the form of the external reference for C programs. When you write your native methods in PL/I and follow the rules above for naming your PL/I subroutines' external references, the javah step is unnecessary for PL/I native methods.

    Objects passed to and from PL/I procedures

    The procedure, 'GetWine' is called from the wineSamp class and is passed two parameters explicitly. In addition, Java always passes two other parameters each time it calls a native method. The first parameter is a pointer to the Java Native Interface environment (JNIEnv) and the second is a 'this' pointer to the object that is making the call. The native program dereferences the JNIEnv pointer (dJNIEnv) when calling back to the Java environment to execute Java methods and read Java Object fields. The 'this' pointer can be used to find out information about the calling Java Object that the native program may find useful in its operation.

    Consider this sample call from a Java program:

      String[] string2 = GetWine( string1, dbObj.getDeBug(dbObj) );
    

    The procedure statement of the receiving native PL/I program would look like this:

      GetWine: Proc( JNIEnv , myJObject, myJString, mydbBool )
         external( "_Java_wineSamp_GetWine" )
         returns( pointer byvalue )
         options( linkage(stdcall) byvalue );
    

    The first parameter received, "JNIEnv", is the Java Native Interface Environment pointer. The second parameter received, "myJObject", is the 'this' pointer to the Java Object which is making the native method call. The third parameter is a pointer to a Java String Object, and the fourth is the boolean value.

    In the PL/I program, the receiving parameters would be declared as follows:

      Dcl JNIEnv       pointer byvalue ;   /* Declared in jni.cpy */
      Dcl myJObject    type jobject;
      Dcl myJString    type jstring;
      Dcl mydbBool     type jboolean;
    

    The declarations for all the necessary PL/I types, Java APIs, and other miscellaneous variables are contained in the jni.cpy and jni_md.cpy include files provided with the PL/I product.

    Each of these PL/I subroutines also returns a reference to a Java Object that contains the answer set. This is done by returning a pointer byvalue to the calling Java program.

    Understanding Java Objects from within PL/I

    In Java, most everything is a Java Object. The exceptions are a small group of Java primitives. In Java, you manipulate the Java Object through methods, not directly like you would a PL/I variable.

    PL/I also needs to use Java methods to manipulate Java Objects. This is done through the reference to the Java Native Interface Environment (JNIEnv) that Java passes to PL/I with each native method call. For example, PL/I needs to unpack a Java String Object before PL/I can understand it. To do this, PL/I would use the Java Native Interface method "GetStringUTFChars". This is how it would look:

     pliStringPtr =
         dJNIEnv->GetStringUTFChars(JNIEnv, myjString, addr(myBool) );
    
    Notice how the Java Native Interface Environment pointer is dereferenced as "dJNIEnv" when it is used to reference the method "GetStringUTFChars".

    A complete description of the Java Native Interface and how it can be used from a native language is beyond the scope of this little example. To learn more, you need to find a good book that has detailed descriptions and many examples. Please refer to "References and Resources" for a recommendation.

    Calling your PL/I native methods

    The actual calls to the PL/I native methods are fairly uncomplicated considering all of the preparation that must be done to make them work.

    The sequence of Java statements to call the first PL/I procedure, 'GetWine', from the Java program looks like this:

      string1 = myChoice.getSelectedItem();
      String[] string2 = GetWine( string1, dbObj.getDeBug(dbObj) );
    

    The idea of this call is to get the selected value from a listbox (a wine variety in this application), pass it to the PL/I routine which then returns all the wines in our wine cellar of that variety.

    The first java statement gets the selected item from the listbox myChoice and loads it into a Java String Object string1. The next statement calls the 'GetWine' method and passes it the Java String Object,string1, containing the selected wine variety, and a boolean value used for debugging purposes. You will notice that the boolean value is actually the value returned from the dbObj.getDeBug() method which asks the debug object, dbObj, for its current state, either 'True' or 'False'.

    The second call to GetDet(....) is very similar to the first, therefore no additional explanation is required.


    Summarizing what you have learned

    You have just scratched the surface regarding the Java programming language. Perhaps you now have a greater understanding of the value of calling a native programming language from Java. You have seen the steps to create, implement, and use a Java native method to call a PL/I program.

    While this sample application illustrates the basics of using Java native methods, there is still much more to learn. A more interactive GUI, some networking, graphics, and animation could easily be added to enhance this application. Hopefully, you now have the foundation you need to get started into the world of the internet and intranet. Once you take the first step, you are only limited by your imagination (or that of your employer).


    References and Resources

    Places to download the Java Development kits for free:

    IBM Java Development Kit 1.1.8 for OS/2:
    http://techsupport.services.ibm.com/asd-bin/doc/en_us/java/f-feat.htm

    Sun Microsystems Java Development Kit 1.1.8 for Windows:
    http://java.sun.com/products/jdk/1.1/

    A good book about the Java Native Interface:
    "Essential JNI, Java Native Interface" by Rob Gordon
    Prentice Hall, 1998