J2VMS: Exploiting OpenVMS from Java
User's Guide & Release Notes


Previous Contents

2.3.2 Passing Arguments By Reference

The J2VMS class vs.ByRef is used to pass arguments by reference (by address). It can be used to pass many data types. Table 2-2 summarises each of the supported types and their usage by native routines.

Table 2-2 Summary of Native Usage of Java Objects Passed by Descriptor
Java Class/Primitive Type Writeable
byte No
int No
long No
short No
byte[] Yes
int[] Yes
long[] Yes
short[] Yes
java.lang.Byte Yes
java.lang.Integer Yes
java.lang.Long Yes
java.lang.Short Yes
java.lang.String No
vs.Cmem Yes
vs.VmsStruct Yes

Note

There is currently no support for passing a java.lang.StringBuffer object by reference. However, this will appear in a future release of J2VMS.

All object and arrays passed by reference can be used to receive results. There is support for passing primitive types by reference. However, these are convenience constructors and cannot be used to receive a result. This is much the same problem as passing a java.lang.String object by descriptor (seen in the Section 2.3.1). Example 2-3 demonstrates the usefulness of being able to pass primitive types and java.lang.String objects as routine inputs.

Example 2-3 Copying A java.lang.String Object to Descriptor

import java.lang.*; 
import vs.*; 
import vs.starlet.DSC; 
 
public class desc 
{ 
 
    public static void main(String args[]) 
    { 
        LibRoutines lib = new LibRoutines(); 
        VmsStruct descriptor = new VmsStruct(DSC.DSC$C_D_BLN); 
        String buffer = "hello, world"; 
 
        descriptor.put(DSC.DSC$W_MAXSTRLEN, 0); 
        descriptor.put(DSC.DSC$B_DTYPE, DSC.DSC$K_DTYPE_T); 
        descriptor.put(DSC.DSC$B_CLASS, DSC.DSC$K_CLASS_D); 
        descriptor.put(DSC.DSC$A_POINTER, 0); 
 
        lib.lib$scopy_r_dx(new VMSparam[] { 
                               new ByRef(buffer.length()), 
                               new ByRef(buffer), 
                               new ByRef(descriptor) 
                           }); 
 
        lib.lib$put_output(new VMSparam[] { 
                               new ByRef(descriptor) 
                           }); 
    } 
 
} 

2.3.3 Passing Arguments By Value

The J2VMS class vs.ByVal is used to pass arguments by value. Table 2-3 lists the supported argument types passed by value.

Table 2-3 Java Classes And Primitive Types That Can Be Passed By Value
Java Class/Primitive Type  
byte  
int  
long  
short  
java.lang.Byte  
java.lang.Integer  
java.lang.Long  
java.lang.Short  

Arguments passed by value can be altered by called routines. However, as with compiled languages the results are lost on return.

2.4 Calling a Native Routine

Calling the native routine is done by passing an array of vs.VMSparam objects to the call method of the vs.SystemCall.

Example 2-4 is a complete example that builds on the previous sections to declare an external routine reference, construct an argument list and finally call the native routine.

Example 2-4 Calling LIB$CHAR from Java

import java.lang.*; 
import vs.*; 
 
public class chr 
{ 
    public static void main(String[] args) 
    { 
        /* Declare result storage, essentailly a dynamic string 
         * string descriptor. 
         */ 
        StringBuffer result = new StringBuffer(); 
 
        /* Declare external reference to routine LIB$CHAR. 
         */ 
        SystemCall lib$char = new SystemCall("LIB$CHAR", "LIBRTL"); 
 
        /* Call the native routine. Here the argument list is constructed 
         * inline so that it looks more like a regular call. 
         */ 
        lib$char.call(new VMSparam[] { 
                          new ByDesc(result), 
                          new ByRef(65) 
                      }); 
 
        /* Output the result received from LIB$CHAR. 
         */ 
        System.out.println("ASCII 65 = " + result); 
    } 
} 

There are times when it is not convenient to declare many routines individually within each method that uses them. Libraries of external routine references can be gather in a class. The most popular examples of this are probably the vs.SystemServices and vs,LibRoutines classes. Similar libraries can also be constructed using the Java language backend for the Structure Definition Language (SDL) compiler.

Example 2-5 shows the code in Example 2-4 after it has been rearranged to take advantage of the vs.LibRoutines class.

Example 2-5 Calling LIB$CHAR from Java Using vs.LibRoutines

import java.lang.*; 
import vs.*; 
 
public class chr2 
{ 
    public static void main(String[] args) 
    { 
        /* Declare result storage, essentailly a dynamic string 
         * string descriptor. 
         */ 
        StringBuffer result = new StringBuffer(); 
 
        /* "Include" vs.LibRoutines. This is similar to C where the 
         * following might be used to include all routines from 
         * SYS$LIBRARY:LIBRTL.EXE. 
         */ 
        LibRoutines lib = new LibRoutines(); 
 
        /* Call the native routine. Here the argument list is constructed 
         * inline so that it looks more like a regular call. 
         */ 
        lib.lib$char(new VMSparam[] { 
                         new ByDesc(result), 
                         new ByRef(65) 
                     }); 
 
        /* Output the result received from LIB$CHAR. 
         */ 
        System.out.println("ASCII 65 = " + result); 
    } 
} 

As can be seen in Example 2-5 there is no longer any need to call the call method. The name of the routine is now used to make the call. The advantage of using the vs.SystemServices and vs.LibRoutines classes or classes generated from SDL is that it is now possible to call a range of routines present in the class.

2.5 Structure Declaration

The Java language has support for classes. These can be likened to OpenVMS native structures. However, as far as physical storage and arrangement there is very little that is similar. It is not possible to easily and uniformly map a native OpenVMS data structure to a Java class. Some element of manual human intervention is required. This is why J2VMS provides the vs.VmsStruct and vs.FieldDescriptor classes. With the use of these two classes access to OpenVMS data structures becomes simple uniform and easy to understand.

Both these classes are based on the mechanism used by the BLISS system programming language for accessing structures. To read further on the BLISS language please see the Associated Documents section.

Structures are allocated internally as an array of bytes and accessed through the class vs.VmsStruct. The target byte array can be allocated by the class constructor or supplied by the caller. From this point forward it is now possible to manipulate the byte array using the put and get methods of the VmsStruct class.

Example 2-6 demonstrates how to allocate storage for an Record Management System (RMS) File Access Block (FAB) structure in Java.

Example 2-6 Allocating a FAB in Java

import vs.*; 
import vs.starlet.FAB; 
   .
   .
   .
VmsStruct fab = new VmsStruct(FAB.FAB$S_FABDEF); 

Example 2-7 demonstrates how to allocate the same structure in the C language.

Example 2-7 Allocating a FAB in C

#include <fabdef.h> 
   .
   .
   .
struct FAB fab; 

Lastly, Example 2-8 demonstrates how to declare a FAB in the BLISS language. The BLOCK attribute can be thought of as the equivalent of the Vs.VmsStruct constructor.

Example 2-8 Allocating a FAB in BLISS

library 'sys$library:starlet'; 
   .
   .
   .
local 
    fab : block[FAB$S_FABDEF, byte]; 

2.6 Structure Manipulation

Structures allocated with the vs.VmsStruct class can be manipulated using the get and put methods. These methods are used, combined with vs.FieldDescriptor objects, to alter specific regions of the byte array target of the VmsStruct object. Each object declares a storage area described in terms of bit and byte offsets from the beginning of a byte array.

Although cumbersome and a little involved, vs.FieldDescriptor objects do allow complete access to any part of the byte array managed by a VmsStruct class. It is recommended that the Structure Definition Language (SDL) be used to declare data structures that can then be translated into FieldDescriptor declarations which can be used with J2VMS.

For further detail on using the SDL language and compiler as well as details of the J2VMS extension to the SDL compiler, see the Associated Documents section at the beginning of this manual.

Figure 2-1 describes that layout of a string descriptor in memory. Example 2-9 demonstrates how this data structure is declared using vs.FieldDescriptor objects.

Figure 2-1 String Descriptor Layout


NL:

DSC$B_DTYPE DSC$B_CLASS DSC$W_LENGTH 0
DSC$A_POINTER
4

Example 2-9 String Descriptor Declaration in Java

import vs.FieldDescriptor; 
 
public class DSCDEF 
{ 
    public static final FieldDescriptor dsc$w_length = 
                                        new FieldDescriptor(0, 0, 16, 0); 
    public static final FieldDescriptor dsc$b_dtype = 
                                        new FieldDescriptor(2, 0, 8, 0); 
    public static final FieldDescriptor dsc$b_class = 
     new FieldDescriptor(3, 0, 8, 0); 
    public static final FieldDescriptor dsc$a_pointer = 
     new FieldDescriptor(4, 0, 32, 0); 
} 

Example 2-10 demonstrates the same declaration in BLISS. It is easy when comparing these examples to see the heritage of the J2VMS method.

Example 2-10 String Descriptor Declaration in Java

field dscdef = 
set 
    dsc$w_length  = [  0,  0, 16,  0 ], 
    dsc$b_dtype   = [  2,  0,  8,  0 ], 
    dsc$b_class   = [  3,  0,  8,  0 ], 
    dsc$b_pointer = [  4,  0, 32,  0 ] 
tes; 

Lastly, Example 2-11 shows the same declaration again. However, this time it is done using PL/I.

Example 2-11 String Descriptor Declaration in PL/I

declare 1 dscdef based, 
        2 dsc$w_length fixed binary(15), 
        2 dsc$b_dtype fixed binary(7), 
        2 dsc$b_class fixed binary(7), 
        2 dsc$a_pointer pointer; 

2.6.1 Cmem

The J2VMS class vs.Cmem is an interface to the C Run-Time Library memory allocation and deallocation routines malloc and free. This class is particularly useful when it comes to allocate storage that must evade the Java garbage collector. An instance of this might be to allocate storage that is referenced by a structure.

Example 2-12 demonstrates a common use of the Cmem class. In this example Cmem is used to allocate storage for a NAML block that can then be referenced by a FAB block. The output storage for the resultant filename is also a Cmem class.

Example 2-12 vs.Cmem Usage Demonstration

import java.lang.*; 
import java.lang.reflect.Array; 
import vs.*; 
import vs.starlet.FAB; 
import vs.starlet.NAM; 
import vs.starlet.SS; 
import vs.starlet.STS; 
 
public class parse 
{ 
    public static void main(String[] args) 
    { 
        VmsStruct fab = new VmsStruct(FAB.FAB$S_FABDEF); 
        VmsStruct naml = new VmsStruct(NAM.NAML$S_NAMLDEF); 
        Cmem cfab = new Cmem(FAB.FAB$S_FABDEF); 
        Cmem cnaml = new Cmem(NAM.NAML$S_NAMLDEF); 
        Cmem long_filename; 
        Cmem long_result = new Cmem(NAM.NAML$C_MAXRSS); 
        int sstatus = SS.SS$_NORMAL; 
        SystemServices sys = new SystemServices(); 
 
        if ((Array.getLength(args) <= 0) 
            || args[0].toUpperCase().startsWith("-H")) 
        { 
            System.out.println("Usage:"); 
            System.out.println("  [java-cmd] parse -h | <filename>"); 
            return; 
        } 
 
        /* Allocate memory region for input filename and copy it in. 
         */ 
        long_filename = new Cmem(args[0].length()); 
        long_filename.copyin(args[0]); 
 
        /* Initialize tha NAML... 
         */ 
        naml.put(NAM.NAML$B_BID, NAM.NAML$C_BID); 
        naml.put(NAM.NAML$B_BLN, NAM.NAML$K_BLN); 
        naml.put(NAM.NAML$L_LONG_FILENAME, long_filename.getPeer()); 
        naml.put(NAM.NAML$L_LONG_FILENAME_SIZE, long_filename.length()); 
        naml.put(NAM.NAML$L_LONG_RESULT, long_result.getPeer()); 
        naml.put(NAM.NAML$L_LONG_RESULT_ALLOC, long_result.length()); 
 
        /* Initialize the FAB... 
         */ 
        fab.put(FAB.FAB$B_BID, FAB.FAB$C_BID); 
        fab.put(FAB.FAB$B_BLN, FAB.FAB$K_BLN); 
        fab.put(FAB.FAB$W_IFI, 0); 
        fab.put(FAB.FAB$L_FNA, -1); 
        fab.put(FAB.FAB$B_FNS, 0); 
        fab.put(FAB.FAB$L_NAM, cnaml.getPeer()); 
 
        /* Copy the NAML block into the memory storage. 
         */ 
        cnaml.copyin(naml); 
 
        /* Now we do the parse... 
         */ 
        sstatus = sys.sys$parse(new VMSparam[] { 
                                    new ByRef(fab), 
                                    new ByVal(0), 
                                    new ByVal(0) 
                                }); 
        if (!STS.$VMS_STATUS_SUCCESS(sstatus)) 
        { 
            sys.sys$exit(new VMSparam[] { 
                             new ByVal(sstatus) 
                         }); 
        } 
 
        /* Copy the NAML from the Cmem object back to the VmsStruct 
         *.object. 
        cnaml.copyout(naml); 
 
        System.out.println("Original specification = " 
                           + long_filename.copyout()); 
 
        System.out.println("Resultant specification = " 
            + long_result.copyout((int)naml.get(NAM.NAML$L_LONG_RESULT_SIZE)) 
   } 
} 

2.7 OpenVMS Status Codes

J2VMS provides a set of methods in the STARLET class STS for accessing the different fields of a status code within a longword. These methods are based on the C macros provided the STSDEF module of SYS$LIBRARY:SYS$STARLET_C.TLB. For further documentation on the available methods please consult the J2VMS API Specification. A pointer to this documentation can be found under Associated Documents.

Example 2-13 demonstrates probably the most common use of the $VMS_STATUS_SUCCESS method.

Note

All methods that return a field of only one bit convert their results to boolean. This makes it easier to use these methods as an if expression. All other methods return int results.

Example 2-13 Using$VMS_STATUS_SUCCESS

import java.io.*; 
import java.lang.*; 
import vs.*; 
import vs.starlet.SS; 
import vs.starlet.STS; 
 
public class status 
{ 
    public static void main(String[] args) 
    { 
        int sstatus = SS.SS$_ACCVIO; 
 
        if (STS.$VMS_STATUS_SUCCESS(sstatus)) 
            System.out.println("Status indicates success!"); 
        else 
            System.out.println("Status indicates failure!"); 
    } 
} 


Previous Next Contents