Search code examples
javaibm-midrangerpglerpgjtopen

How to Call RPGIV program from java that returns more than one record


I am calling a RPGIV program from java, the rpgiv program returnes multi record as an output parameter.

I tried the following to return all the rows returned from rpgiv.

   // Define Output Data Structure 
      AS400DataType[] outputData = 
    {
        new AS400Text(20),              // parentOperationsItemId;
        new AS400Text(10),              // parentOperationsItemType;
        new AS400Text(10),              // parentOperationsItemSubType;
        new AS400Text(20),              // parentKnownbyId;
        new AS400Text(10),              // parentInternalStatus;
        new AS400Text(1),               // parentLeafIndicator;
        new AS400Text(20),              // childOperationsItemId;
        new AS400Text(10),              // childOperationsItemType;
        new AS400Text(10),              // childOperationsItemSubType;
        new AS400Text(20),              // childKnownbyId;
        new AS400Text(10),              // childInternalStatus;
        new AS400Text(1),               // childLeafIndicator;
        new AS400Text(10)               // InternalStatus;
    };

AS400Structure [] outputDataConverter2 = new AS400Structure[3];

    outputDataConverter2[0] = new AS400Structure(outputData);
    outputDataConverter2[1] = new AS400Structure(outputData);
    outputDataConverter2[2] = new AS400Structure(outputData);


    Object[] dataInputInformation = 
    {
        sSqlSelect,
        sFetchDirection,
        sOperationsItemId,
        sparentOperationsItemTypeList,
        sparentOperationsItemSubTpeList,
        sparentInternalStatusList,
        schildOperationsItemType,
        schildOperationsItemSubTpeList,
        schildInternalStatusList,
        sLinkStatus
    };


    Object[] dataInputInformationControl = 
    {
        sPosition,
        new BigDecimal(sRowsFetched)
    };


    // Set up the parameter list
    ProgramParameter[] parameterList = new ProgramParameter[4];
    parameterList[0] = new ProgramParameter(7); //ReturnStatus
    parameterList[1] = new ProgramParameter(inputDataConverter.toBytes(dataInputInformation)); //Input
    parameterList[2] = new ProgramParameter(inputDataControlConverter.toBytes(dataInputInformationControl)); //Control
    parameterList[3] = new ProgramParameter(outputDataConverter2[0].getByteLength()*3); //Output



    try 
    {
        // Set the program name and parameter list.
        program.setProgram(programName, parameterList);
        // Run Function
        if (program.run() != true) 
        {
            // Calling Error
            AS400Message[] messagelist = program.getMessageList();
            for (int i = 0; i < messagelist.length; ++i) 
            {
                output[0].ReturnStatus += messagelist[i] + "\n";
            }
        } 
        else 
        {
            // Set the output
            output[0] = new GetPlannedRoute();
            output[1] = new GetPlannedRoute();
            output[2] = new GetPlannedRoute();



            output[0].SetOutput(parameterList, outputDataConverter2[0]);
            output[1].SetOutput(parameterList, outputDataConverter2[1]);
            output[2].SetOutput(parameterList, outputDataConverter2[2]);
        }
    } 

This is in the output class

public void SetOutput(ProgramParameter[] parameterList, AS400Structure outputPlannedRouteConverter) 
    {

        ReturnStatus = P6Entity.CallingRPGFunction.ConvertReturnStatus(parameterList[0]);
        Object[] outputData = (Object[]) outputPlannedRouteConverter.toObject(parameterList[3].getOutputData());
        parentOperationsItemId = ((String) outputData[0]).trim();
        parentOperationsItemType = ((String) outputData[1]).trim();
        parentOperationsItemSubType = ((String) outputData[2]).trim();
        parentKnownbyId = ((String) outputData[3]).trim();
        parentInternalStatus = ((String) outputData[4]).trim();
        parentLeafIndicator = ((String) outputData[5]).trim();

        childOperationsItemId = ((String) outputData[6]).trim();
        childOperationsItemType = ((String) outputData[7]).trim();
        childOperationsItemSubType = ((String) outputData[8]).trim();
        childKnownbyId = ((String) outputData[9]).trim();
        childInternalStatus = ((String) outputData[10]).trim();
        childLeafIndicator = ((String) outputData[11]).trim();

        InternalStatus = ((String) outputData[12]).trim();
    }

I am not sure how to define parameterList[3] to be able to receive multiple rows back or multiple data structures. And how to get a specific instance of the output parameterList[3].

The RPGIV code:

https://www.dropbox.com/s/a29wf1ft0f07sx1/functionCode.txt?dl=0

The * FetchedData Occures OCCURS(64) INZ is the output data set that I want to return to java.


Solution

  • Edited to show how to convert a packed value.

    Let's cut this down a bit. Here is a small RPG program that has a similar structure to yours:

     D V00001          DS                  OCCURS(64)
     D  F0000G                       20A
     D  F0000H                       10A
     D  F0000I                       10A
     D  F0000J                       20A
     D  F0000K                        9p 0
     D  F0000L                        1A
     D  F0000M                       20A
     D  F0000N                       10A
     D  F0000O                       10A
     D  F0000P                       20A
     D  F0000Q                       10A
     D  F0000R                        1A
     D  F0000S                       10A
    
     c     *entry        plist
     c                   parm                    v00001
    
       // populate the first entry
       %occur(v00001) = 1;
       F0000G = *ALL'1234567890';
       F0000H = *ALL'A';
       F0000I = *ALL'B';
       F0000J = *ALL'C';
       F0000K = 123456789;
       F0000L = *ALL'E';
       F0000M = *ALL'F';
       F0000N = *ALL'G';
       F0000O = *ALL'H';
       F0000P = *ALL'I';
       F0000Q = *ALL'J';
       F0000R = *ALL'K';
       F0000S = *ALL'a';
    
       // populate the 2nd entry
       %occur(v00001) = 2;
       F0000G = *ALL'1234567890';
       F0000H = *ALL'1234567890';
       F0000I = *ALL'1234567890';
       F0000J = *ALL'1234567890';
       F0000K = 200;
       F0000L = *ALL'1234567890';
       F0000M = *ALL'1234567890';
       F0000N = *ALL'1234567890';
       F0000O = *ALL'1234567890';
       F0000P = *ALL'1234567890';
       F0000Q = *ALL'1234567890';
       F0000R = *ALL'1234567890';
       F0000S = *ALL'b';
    
       // populate the third entry
       %occur(v00001) = 3;
       F0000G = *ALL'1234567890';
       F0000H = *ALL'1234567890';
       F0000I = *ALL'1234567890';
       F0000J = *ALL'1234567890';
       F0000K = 300;
       F0000L = *ALL'1234567890';
       F0000M = *ALL'1234567890';
       F0000N = *ALL'1234567890';
       F0000O = *ALL'1234567890';
       F0000P = *ALL'1234567890';
       F0000Q = *ALL'1234567890';
       F0000R = *ALL'1234567890';
       F0000S = *ALL'c';
    
       // reset back to the beginning
       %occur(v00001) = 1;
       dump(a);
    
       *inlr = *on;
    

    Here is the Java (I AM NOT A Java PROGRAMMER!) that successfully reads the various 'records':

    public String testSO(AS400 system, String programName) {
        boolean success = false;
        final int ONE_ROW_LEN = 147;
        final int DS_ROWS = 64;
        AS400Text dsText = new AS400Text(ONE_ROW_LEN * DS_ROWS);
        AS400Text p0000g = new AS400Text(20);
        AS400Text p0000h = new AS400Text(10);
        AS400Text p0000i = new AS400Text(10);
        AS400Text p0000j = new AS400Text(20);
        int p0000k;  // packed(9, 0) is 5 bytes
        AS400Text p0000l = new AS400Text( 1);
        AS400Text p0000m = new AS400Text(20);
        AS400Text p0000n = new AS400Text(10);
        AS400Text p0000o = new AS400Text(10);
        AS400Text p0000p = new AS400Text(20);
        AS400Text p0000q = new AS400Text(10);
        AS400Text p0000r = new AS400Text( 1);
        AS400Text p0000s = new AS400Text(10);
        String ds = null;
    
        String returnString = null;
    
        try
        {
            ProgramCall program = new ProgramCall(system);
    
            // Set up the parameter list
            ProgramParameter[] parameterList = new ProgramParameter[1];
            parameterList[0] = new ProgramParameter(ONE_ROW_LEN * DS_ROWS); 
            program.setProgram(programName, parameterList);
            success = program.run();
    
            if(success!=true){
                AS400Message[] messagelist = program.getMessageList();
                System.out.println("\nMessages received:\n");
                for (int i = 0; i < messagelist.length; i++) {
                    System.out.println(messagelist[i]);
                }
            } else {
                // RPG is returning a giant chunk of memory
                //allBytes = parameterList[0].getOutputData();
                ds = (String)dsText.toObject(parameterList[0].getOutputData());
                System.out.println("ds=" + ds);
                System.out.println("ds len=" + ds.length());
    
                // Need to index our way into the block of memory
                // zero-based!
                int row = 0;
                int x = row * ONE_ROW_LEN;
                System.out.println("x=" + x);
    
                // parse out the individual elements for this row
                int len = p0000g.getByteLength();
                String s0000g = ds.substring(x, x+len);
                x += len;
                len = p0000h.getByteLength();
                String s0000h = ds.substring(x, x+len);
                x += len;
                len = p0000i.getByteLength();
                String s0000i = ds.substring(x, x+len);
                x += len;
                len = p0000j.getByteLength();
                String s0000j = ds.substring(x, x+len);
    
            // this is packed(9, 0)
            x += len;
            len = 5;
            byte[] b0000k = dsText.toBytes(ds.substring(x, x+len));
            BigDecimal d0000k = (BigDecimal)new AS400PackedDecimal(9, 0).toObject(b0000k);
            p0000k = d0000k.intValue();
            String s0000k = d0000k.toString();
    
                x += len;
                len = p0000l.getByteLength();
                String s0000l = ds.substring(x, x+len);
                x += len;
                len = p0000m.getByteLength();
                String s0000m = ds.substring(x, x+len);
                x += len;
                len = p0000n.getByteLength();
                String s0000n = ds.substring(x, x+len);
                x += len;
                len = p0000o.getByteLength();
                String s0000o = ds.substring(x, x+len);
                x += len;
                len = p0000p.getByteLength();
                String s0000p = ds.substring(x, x+len);
                x += len;
                len = p0000q.getByteLength();
                String s0000q = ds.substring(x, x+len);
                x += len;
                len = p0000r.getByteLength();
                String s0000r = ds.substring(x, x+len);
                x += len;
                len = p0000s.getByteLength();
                String s0000s = ds.substring(x, x+len);
    
    
                returnString = s0000s;
                System.out.println("Return=" + returnString);
                System.out.println("g=" + s0000g);
                System.out.println("h=" + s0000h);
                System.out.println("i=" + s0000i);
                System.out.println("i=" + s0000i);
                System.out.println("j=" + s0000j);
                System.out.println("k=" + s0000k);
                System.out.println("l=" + s0000l);
                System.out.println("m=" + s0000m);
                System.out.println("n=" + s0000n);
                System.out.println("o=" + s0000o);
                System.out.println("p=" + s0000p);
                System.out.println("q=" + s0000q);
                System.out.println("r=" + s0000r);
                System.out.println("r=" + s0000s);
            }
    
        } catch (Exception e) {
            System.out.println("\ne:\n");
            System.out.println(e);
            System.out.println("\nStack trace:\n");
            e.printStackTrace();
    
        }
        return returnString;
    }
    

    The key part to understand in the Java are that with this design, Parameter.getOutputData() is returning byte[]. I am not a Java programmer, so my Java code is ugly. I cast the returned byte[] to String and assigned it as a block to ds. I then brute-forced a section of code that substrings out the individual variables one by one. If I knew more Java I'd probably have put that junk in a constructor and maybe exposed it as a List.

    Having posted all that, there is no way I would operate this way with production code. I would have the IBM programmers write me a wrapper around the SuperUltimateBlockFetch - that wrapper would call SuperUltimateBlockFetch and build a result set for use by Java. They could even make it into a stored procedure. This would decouple your dependence on understanding the internals of how the RPG structure is built and make it much more natural to deal with the individual variables in the Java code. Then all you would do would be to call the stored procedure and write a while rs.next() loop.