longpelaexpertise.com.au/ezine/HLASMfromJava.php?ezinemode=printfriend

LongEx Mainframe Quarterly - August 2009

technical: How to Call HLASM from Java

Java and High Level Assembler (HLASM) are often regarded as the Montagues and Capulets of z/OS. However there are occasions where you need to call an HLASM program from Java. This article shows how.

Introduction

High Level Assembler (HLASM) has been around in one form or another from the birth of the z/Series mainframe. And because of this, there is a huge amount of legacy HLASM code still being used by mainframe users. What's more, there are still some things that are best done in HLASM - from z/OS user exits to performance critical code.

Java is almost the exact opposite. The new kid on the block, Java on z/OS has yet to gain much traction. However Java programmers with no z/OS experience can now develop new code, and even port existing programs to z/OS. This makes Java a very appealing option.

But what if you need to call an HLASM program from Java? There could be many reasons for this, such as:

  • There is an existing HLASM routine that you want to call from Java.
  • You need to call another z/OS routine, and need an HLASM routine to sit in-between to handle incompatible parameters and environments.
  • You need to get some z/OS information that isn't available to Java.
  • You need to do something that you can't do in Java.

This article will show how this is done by providing an example. We will have an HLASM routine that can return either:

  • the z/OS host name (or more specifically, the z/OS SMFID that identifies the name of the z/OS image), or
  • the Sysplex name.

This routine will be called from a Java program that provides a parameter. This parameter will determine whether the host name or Sysplex name is returned.

To do this we will actually have four programs:

  1. The HLASM routine: ASMINF.
  2. The Java Native Interface (JNI) routine: JNIzOS.c - written in C.
  3. The Java program zOSInfo - providing the classes needed to call our interface.
  4. The Java program callHlasm- a program to test our interface.

1. The HLASM Program ASMINF

Program Description

This program will be passed a parameter holding the address of one 8 byte area. On input, this area will hold either:

  • HOST - requesting the z/OS host name.
  • SYSPLEX - requesting the Sysplex name.

If neither of these values is present, the routine will exit with a return code of 8.

The routine will insert the host or Sysplex name in this same area, and will exit with a return code of 0.

ASMINF Listing

*============================================================
*                                                           
* ASMINF - Provide z/OS Host or Sysplex Name            
*                                                       
*============================================================
ASMINF   EDCXPRLG PARMWRDS=1,BASEREG=R10,EXPORT=YES      
         L     R9,0(R1)                R9 -> Input area   
                                          
* -----------------------------------------------------------
* Check the value of our input area, and get Sysplex/Host  
* as required                                
* -----------------------------------------------------------
         CLC   0(7,R9),=C'SYSPLEX'     Getting sysplex?    
         BE    SYSPLEX                 Yes - Go get it 
         CLC   0(4,R9),=C'HOST'        Getting host?  
         BE    HOST                    Yes - Go get it   
         LA    R3,8                    Else Bad Return Code 
         B     EXIT                      
                                           
* -----------------------------------------------------------
* Get the Host Name from the SMCA Control Block
* -----------------------------------------------------------
HOST     DS    0H                        
         LLGT  R2,CVTPTR               R1 -> CVT     
         LLGT  R2,CVTSMCA-CVT(R2)      R2 -> SMCA     
         MVC   0(L'SMCASID,R9),SMCASID-SMCABASE(R2) SMFID
         B     EXIT0                   And Exit
                                                            
* -----------------------------------------------------------
* Get the Sysplex Name from the Extended CVT
* -----------------------------------------------------------
SYSPLEX  DS    0H                             
         LLGT  R2,CVTPTR               R2 -> CVT        
         MVC   0(L'ECVTSPLX,R9),ECVTSPLX-ECVT(R2)   Sysplex
         B     EXIT0                   And Exit
                                                           
* -----------------------------------------------------------
* Zero Return Code and Exit                  
* -----------------------------------------------------------
EXIT0    DS    0H                                  
         XR    R3,R3                   Zero Return Code      
EXIT     DS    0H                                            
         EDCXEPLG                      Return to caller
		 
* -----------------------------------------------------------
* Mapping Macros and DSECTs                 
* -----------------------------------------------------------
         CVT   DSECT=YES               Map CVT
		 IHAECVT                       Map ECVT
		 IEESMCA                       Map SMCA

ASMINF Explanation

  1. This program accesses standard z/OS control blocks to get the information required:
    • CVT (Common Vector Table) to get addresses of other control blocks.
    • ECVT (Extended CVT) to get the Sysplex name.
    • SMCA (SMF Control Area) to get the host name.

    More information about these control blocks can be found in the relevant IBM z/OS Data Area manuals.

  2. From Java SDK 1.4, all Java JNI calls expect to call an XPLINK module. This means our HLASM program must be XPLINK. To achieve this:
    • The program starts with the EDCXPRLG macro and finishes with EDCXEPLG. These macros are similar to the Language Environment (LE) CEESTART and CEETERM macros, and are documented in the IBM z/OS C/C++ Programming Guide.
    • ASMINF adheres to the XPLINK register usage conventions
  3. Our module passes the return code back in R3, which is returned to C.
  4. ASMINF can be called in either 31 or 64 bit mode. However 31 bit programs cannot call 64 bit modules, or vice versa. So ASMINF must be in the same addressing mode as the JNI module calling it. The only way to achieve this is to have two HLASM modules:
    • ASMINF - 31 bit
    • ASMINF64 - 64 bit
    ASMINF64 will look like:
    ASMINF64 CELQPRLG PARMWRDS=1,BASEREG=R10,EXPORT=YES  
             LG    R9,0(R1)                R9 -> Input area
    (same code as for ASMINF)
    * ----------------------------------------------------
    * Zero Return Code and Exit                 
    * ----------------------------------------------------
    EXIT0    DS    0H                              
             XR    R3,R3                   Zero Return Code
    EXIT     DS    0H                                    
             CELQEPLG                      Return to caller

    This is identical to ASMINF except for the CELQPRLG and CELQEPLG macros (and the 64 bit load of the parameter address). These macros do exactly the same job as EDCXPRLG and EDCXEPLG - and their parameters are the same. They are documented in the IBM z/OS Language Environment Programming Guide for 64-bit Addressing Mode manual.

  5. The 31 bit ASMINF has been coded to be 64 bit compliant in all other ways. For example the LLGT instruction has been used instead of LA when loading the (31 bit) pointers to the ECVT and SMCA control blocks from the CVT control block.

Assembling ASMINF

Because ASMINF is an XPLINK module it needs to be a DLL. This means that we will be assembling with the RENT and GOFF HLASM options.

Binding ASMINF

If ASMINF is going to be called statically then there's no need to bind it - that's done when binding JNIzOS. However if called dynamically then it must be bound as a DLL, and you must save the side file for use with JNIzOS.

2. The JNI Program JNIzOS

Program Description

JNIzOS is a C program that sits between our Java classes and ASMINF. It accepts a string parameter from Java, passes this onto ASMINF, and passes back the value returned by ASMINF.
If the return code from ASMINF is not zero (meaning that an error has occurred), then JNIzOS returns the string "(invalid)" to its Java caller.

JNIzOS Listing

/* ------------------------------------------------------   
   Java declaration                 
   ------------------------------------------------------ */
JNIEXPORT jstring JNICALL Java_zOSInfo_showZos     
  (JNIEnv *, jobject, jstring);                
                                              
/*========================================================  
 Mainline Code                                 
 ======================================================== */
JNIEXPORT jstring JNICALL                       
Java_zOSInfo_showZos(JNIEnv *env,jobject obj,jstring jParm)  
{                                                
                                                   
   /* --- Variables ------------------------------------- */
    int rc;                            /* rc from ASMINF  */
    char *passarea;                    /* ptr to parms    */
                                                  
   /* --- Get the parm input, and convert to EBCDIC  ---- */
    const char* msg=(*env)->GetStringUTFChars(env,jParm,0); 
    __atoe((char*) msg);                     
    (*env)->ReleaseStringUTFChars(env, jParm, msg);
   
   /* --- Setup 8 Byte Area to pass (leave space for NULL)*/
    passarea = malloc(10);             /* Get area        */
    memset(passarea, 0, 10);           /* Clear area      */
    strcpy(passarea,msg);              /* Put parm in     */
                                              
   /* --- Load the correct JNI module: 31 or 64 bit  ---- */
    #  ifdef _LP64                             
       rc = ASMINF64(&passarea);                     
    #else                                          
       rc = ASMINF(&passarea);                  
    #endif                                      
                                              
   /* --- If bad return code from HLASM, modify passarea  */
    if (rc > 0) strcpy(passarea, "(invalid)");         
                                              
   /* --- Convert area returned by HLASM back to ASCII  - */
    __etoa((char*) passarea);                        
                                                
   /* --- And return it --------------------------------- */
    return (*env)->NewStringUTF(env, passarea);      
                                             
}                                      /* main            */

JNIzOS Explanation

JNIzOS is a standard Java JNI program with some special features:

  1. It uses the __atoe and __etoa functions to convert between EBCDIC and ASCII. These functions use the default Locale. We convert the parameters passed from Java to EBCDIC, and the values from ASMINF to ASCII.
  2. It does a standard call to the HLASM program - using the _LP64 macro to determine which HLASM program to call, the 31 or 64 bit version.
  3. We again have the problem where 31 bit programs can't call 64 bit programs and vice versa. So once again there will be two versions of this code:
    • JNIzOS - 31 bit version
    • JNIzOS64 - 64 bit version.
    We can use the same code, but use the LP64 compiler option for the 64 bit version.

Compiling JNIzOS

  1. As JNIzOS is an XPLINK module, the XPLINK compiler option must be used.
  2. If not compiling with the EXPORTALL function, then a #pragma statement looking like:
    #pragma export(Java_zOSInfo_showZos)
    is needed. Without this, our Java class won't find the zOSInfo function.

Binding JNIzOS

If dynamically calling ASMINF:

  1. The side file generated by ASMINF must be specified as additional input to the binder
  2. ASMINF must exist in a place that can be loaded by JNIzOS. Or in other words, in either the z/OS linklist, STEPLIB or libpath. Because this can at times be difficult and prone to errors, it may be more robust to statically call ASMINF.

Additionally:

  1. JNIzOS must be bound as an XPLINK dll.
  2. If running Java SDK 1.5 or later, the module name JNIzOS is fine. However if we are running an earlier Java SDK, this name must be in the format libxxxxx.so - for example libJNIzOS.so.
  3. JNIzOS and JNIzOS64 must be bound into a USS directory in the Java libpath. It cannot be bound in the z/OS linklist or STEPLIB - Java won't find it. You can get around this is by defining an external link in the USS directory that points to the module in the z/OS linklist or STEPLIB. The USS ln command can do this.

The Java Program zOSInfo

Program Description

zOSInfo holds the classes connecting to our JNI module. Standard Java code, it uses the system property com.ibm.vm.bitmode to determine if running in 31 bit (the value is actually 32) or 64 bit mode. If running Java SDK 1.5 or later, the more standard sun.arch.data.model property can also be used here.

zOSInfo Listing

/* -------------------------------------------------------  
   callHlasm - Call ASMINF HLASM module from Java   
   ------------------------------------------------------ */
                                                       
class zOSInfo {                                            
                                                          
    public native String showZos(String parm);             
       static {                                       
          /* --- Get our addressing mode (31 or 64) ----- */
          String arch = 
             System.getProperty("com.ibm.vm.bitmode");
                                                            
          /* --- Load the correct JNI Module ------------ */
          if (arch.equals("64"))                       
             System.loadLibrary("JNIzOS64");               
          else                                      
             System.loadLibrary("JNIzOS");                
       }                                                 
}                                                 

The Java Program callHlasm

Program Description

This program tests our interface. We will call zOSInfo three times, each with a different parameter:

  1. SYSPLEX - to return the Sysplex name
  2. HOST - to return the z/OS SMFID
  3. JUNK - an invalid parameter. Our program will return "(invalid)"

callHlasmSample Listing

/* -------------------------------------------------------
   callHlasm - Call ASMINF HLASM module from Java     
   ------------------------------------------------------ */
                                           
class callHlasm {                             
                                          
   public static void main(String[] args) throws Exception {
       System.out.println("(callHlasm) Started:");   
       zOSInfo a = new zOSInfo();      
                                                
       /* --- Get Hostname ------------------------------ */
       System.out.print("Host: ");           
       System.out.println(a.showZos("HOST")); 
                                         
       /* --- Get Sysplex Name: ------------------------- */
       System.out.print("Sysplex: ");          
       System.out.println(a.showZos("SYSPLEX"));     
                                               
       /* --- Specify an invalid parameter -------------- */
       System.out.print("Bad Parm: ");     
       System.out.println(a.showZos("JUNK"));
                                       
       System.out.println("(callHlasm) Finished");
    }                                         
}    

Conclusion

To be able to call an HLASM module can be invaluable for Java programmers, and it isn't difficult to do. In fact the most difficult part is probably making your HLASM module XPLINK compliant.

References


David Stephens