Support This Project Get i5/OS Programmer's Toolkit at SourceForge.net. Fast, secure and Free Open Source software downloads

i5/OS Programmer's Toolkit: MI Portal

0.2.16

Go back to main page of i5/OS Programmer's Toolkit.

Remarks:
This subproject is currently under the prototype stage.
MI (Machine Interface) Portal is a subproject of i5/OS Programmer's Toolkit . MI Portal is for use by host HLL programs, Java programs, remote clients to issue MI (Machine Interface) instructions on an IBM i server.

What is MI Portal?

The essential of MI Portal is an agent program issuing MI instructions on an IBM i server in behalf of its callers.

Since MI Portal is an agent program and has its own invocation entry (call-stack entry), issuing invocation-related MI instructions via MI Portal need special considerations. For example, issuing the Modify Invocation Authority Attributes (MODINVAU) instruction via MI Portal will never work as expected, since MODINVAU modifies the authority attributes of the invocation that issues the instruction, aka. the invocation of MI Portal itself. Another example is using the Modify Automatic Storage Allocation (MODASA) instruction to allocate automatic storage, since automatic storage is invocation-oriented, and will become invalid when the invocation in which it's allocated does not exist.

Where MI Portal should NOT be used?

In host HLL programs where MI instructions are utilized for performance reasons, you may consider using MI instructions directly instead of MI Portal to save unnecissary program calls.

How does MI Portal work?

Generally, MI Portal works like the following.

inline_dotgraph_1.dot

How does MI Portal support MI pointers?

Just like a programmer cannot code with a programming language when he's forbidden to use the most important data types in that language, programming language or utitlities that do not support MI pointers cannot utilize most of the MI instructions. To allow clients to fully take advantages of MI instructions, MI Portal manages pointer data items generated or referenced by MI instructions requested by clients at the server side. The process of MI Portal managing pointers is transparent to clients, the only thing clients need to do is to replace the each pointer operand with a 16-byte pointer ID (a UUID generated by MI Portal to uniquely identify a pointer data object). For details on support for different type of pointers, please refer to section Support for MI Pointers in MI Portal Reference.

The very beginning examples of using MI Portal to issue MI instructions on an IBM i server

Now, let us show you some very beginning examples of using MI Portal to issue MI instructions on an IBM i server. Hope you find them interesting :)

Note that, all Java examples in this section can be run either at an IBM i server locally or from a remote PC.

Generating a UUID at an IBM i server from Java

The following Java program, uuid.java issues the MI instruction GENUUID (Generate Universal Unique Identifier) to generate a UUID via MI Portal.
import com.ibm.as400.access.*;

public class uuid {

    public static void main(String[] args) {

        byte[] inst_inx = {  // ubin(2) instruction index, hex 0001 for MATMATR
            0x00, 0x02
        };
        byte[] uuid_tmpl = { // length the UUID instruction template is 32
            0x00, 0x00, 0x00, 0x20, // bin(4) bytes-in = 32
            0x00, 0x00, 0x00, 0x00, // bin(4) bytes-out
            0x00, 0x00, 0x00, 0x00, // char(8) reserved
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, // char(16) returned UUID
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00
        };

        AS400 i = new AS400();
        ProgramParameter[] plist = new ProgramParameter[] {
            new ProgramParameter(inst_inx),  // input, ubin(2) instruction index
            new ProgramParameter(uuid_tmpl, 32) // inout, instruction template of GENUUID
        };

        ProgramCall portal = new ProgramCall(i,
                                             "/qsys.lib/i5toolkit.lib/miportal.pgm",
                                             plist
                                             );

        try {
            if(!portal.run())
                System.out.println("Oops!");
            else {
                byte[] tmpl = plist[1].getOutputData();
                String uuid = "";
                long l = 0;
                for(int j = 0; j < 8; j++)
                    l += ((long)tmpl[16 + j]) << ((7 - j) * 8);
                uuid += java.lang.Long.toHexString(l);

                l = 0;
                for(int j = 0; j < 8; j++)
                    l += ((long)tmpl[24 + j]) << ((7 - j) * 8);
                uuid += java.lang.Long.toHexString(l);

                System.out.println("UUID generated by MI instruction GENUUID: " + uuid);
                /* The output might like the following:
                  UUID generated by MI instruction GENUUID: 215f280084b9194cab860003ac117d94
                 */
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

}

Retrieving the LIC VRM of an IBM i server from Java

It's not very easy for host programs or interative users to find out the accurate LIC (Licensed Internal Code) VRM (Version Release Modification). For example, you can start a SST (System Service Tools) session, type 1 (Start a service tool), and then type 7 (Hardware service manager), and check the 'Release' display field; but in most cases a user just hasn't the priviledge to run SST. Fortunately, the MI instruction Materialize Machine Attributes (MATMATR) is very handy to solve this problem. With materialization option hex 020C, you can get the LIC VRM conveniently via the MATMATR instruction with only serveral lines of code. ILE RPG program t120.rpgle is an example.

Here, you'll see a similar Java example of retrieving the LIC VRM of an IBM i server, the difference is that this program uses MI Portal to achieve its job, since there's no way for a Java program to execute MI instructions directly. vrm.java

import com.ibm.as400.access.*;

public class vrm {

    public static void main(String[] args) {

        byte[] inst_inx = {  // ubin(2) instruction index, hex 0001 for MATMATR
            0x00, 0x01
        };
        byte[] matmatr_tmpl = {
            0x00, 0x00, 0x00, 0x10, // bin(4) bytes-in = 16
            0x00, 0x00, 0x00, 0x00, // bin(4) bytes-out
            0x00, 0x00, 0x00, 0x00, // char(6) VRM, char(2) reserved
            0x00, 0x00, 0x00, 0x00
        };
        byte[] matmatr_opt = {  // char(2) materialization option, hex 020C for LIC VRM
            0x02, 0x0C
        };

        AS400 i = new AS400();
        ProgramParameter[] plist = new ProgramParameter[] {
            new ProgramParameter(inst_inx),  // input, ubin(2) instruction index
            new ProgramParameter(matmatr_tmpl, 16), // inout, instruction template of MATMATR
            new ProgramParameter(matmatr_opt)   // input, char(2) materialization option
        };

        ProgramCall portal = new ProgramCall(i,
                                             "/qsys.lib/i5toolkit.lib/miportal.pgm",
                                             plist
                                             );

        try {
            if(!portal.run())
                System.out.println("Oops!");
            else {
                byte[] tmpl = plist[1].getOutputData();

                AS400Text cvt = new AS400Text(6, i); // use the CCSID of the currently connected AS400 object
                String vrm = (String)cvt.toObject(tmpl, 8);
                System.out.println("LIC VRM of the current IBM i server is: " + vrm);
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

}

Retrieving the number of installed processors of an IBM i server in an RPG program

The following ILE RPG program, prcnum.rpgle calls MI Portal to issue the MI instruction Materialize Machine Attributes (MATMATR) with materialization option hex 01DC to retrieve the number of installed process of the current IBM i server.
     d tmpl            ds                  qualified
     d     bi                        10i 0 inz(10)
     d     bo                        10i 0
     d     prc_num                    5u 0

     d opt             s              2a   inz(x'01DC')
     d ent_num         s              5u 0 inz(1)

     c                   call      'MIPORTAL'
     c                   parm                    ent_num
     c                   parm                    tmpl
     c                   parm                    opt
     c     'Processors'  dsply                   tmpl.prc_num
     c                   seton                                        lr

Enqueue a User Queue (USRQ) from Java using the RSLVSP and ENQ instructions

Working with queue objects is quite straitforward in HLL or MI programming. For example, to enqueue a FIFO USRQ, *LIBL/Q007, in an OPM MI program, you probably need to type only a few lines of code like the following:
dcl sysptr q007 auto            ;
dcl dd r-tmpl char(34) auto     ;
dcl dd prefix char(4) auto      ;
        dcl dd msg-len bin(4) def(prefix) pos(1) init(32) ;
dcl dd msg char(32) auto init('QQ')   ;
dcl spcptr msg-ptr auto init(msg)     ;

        cpybla r-tmpl(1:2), x'0A02'       ; /* MI type/subtype code of USRQ */
        cpyblap r-tmpl(3:30), "Q007", " " ; /* object name */
        rslvsp q007, r-tmpl, *, *         ; /* resolve the system pointer to Q007 by symbolic name via the RSLVSP instruction */
        enq q007, prefix, msg-ptr         ; /* enqueue Q007 using the ENQ instruction */

Before the introduction of MI Portal, local Java programs or remote clients cannot achieve the above steps to enqueue a USRQ for reason of lacking support for MI pointers. The following is a Java example (enq.java) that achieve the same job as the above MI code via MI Portal.

import com.ibm.as400.access.*;
import u.*;

public class enq {

    public static void main(String[] args) {

        try {
            byte[] inst_inx = {  // ubin(2) instruction index, hex 0003 for _RSLVSP2
                0x00, 0x03
            };
            RSLVSPTmpl rtmpl = new RSLVSPTmpl(0x0A02, // object type/subtype code of USRQ, hex 0A02
                                              "Q007",
                                              0x0000);// required authority
            ProgramParameter[] plist_rslvsp2 = new ProgramParameter[] {
                new ProgramParameter(inst_inx),  // input, ubbin(2) instruction index
                new ProgramParameter(16),         // output, ptr-ID of the resolved system pointer
                new ProgramParameter(rtmpl.toBytes()) // input, instruction template of RSLVSP
            };

            AS400 i = new AS400();
            ProgramCall portal = new ProgramCall(i,
                                                 "/qsys.lib/i5toolkit.lib/miportal.pgm",
                                                 plist_rslvsp2
                                                 );

            AS400Bin4 bin4 = new AS400Bin4();
            AS400Text ch32 = new AS400Text(32, i);
            if(!portal.run())
                System.out.println("Issuing _RSLVSP2 failed.");
            else {
                byte[] ptr_id = plist_rslvsp2[1].getOutputData();
                String msg = "Hello MI!";

                inst_inx[1] = 0x04; // instruction index of ENQ, hex 0004
                ProgramParameter[] plist_enq = new ProgramParameter[] {
                    new ProgramParameter(inst_inx),
                    new ProgramParameter(ptr_id), // input, char(16) ptr-ID
                    new ProgramParameter(bin4.toBytes(msg.getBytes().length)), // input, message prefix (bin(4) message length and optional message key)
                    new ProgramParameter(ch32.toBytes(msg))  // input, message text
                };
                portal.setParameterList(plist_enq);
                if(!portal.run())
                    System.out.println("Failed to issue the ENQ instruction.");
                else
                    System.out.println("Check the enqueued message using the DSPQMSG command.");
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

}

Listing User Profiles (USRPRFs) on an IBM i Server

To list the names of and/or system pointers to all USRPRFs on an IBM i server, you can use the Materialize Context (MATCTX) instruction to materialize all MI objects with object type code hex 08 in the machine context. To achieve this this job in OPM MI, you might code a little MI program like the following.
/* ii110.emi */

dcl dd opt char(46) auto        ;
dcl spcptr opt-ptr auto init(opt) ;

        cpybrep opt, x'00'      ;
        cpybla opt-ptr->matctx-opt?info-required,
          x"05"                   ;
        cpybla opt-ptr->matctx-opt?select-criteria,
          x"01"                   ; /* select from machine context by object type code */
        cpybla opt-ptr->matctx-opt?obj-type, x'08' ;

dcl spcptr tmpl auto                   ;
        modasa tmpl, 8                 ;
        cpynv tmpl->matctx?bytes-in, 8 ;
        matctx tmpl, *, opt            ;
brk "1"                                ;
dcl dd len bin(4) auto          ;
        cpynv len, tmpl->matctx?bytes-out ;
        modasa tmpl, -8         ;
        modasa tmpl, len        ;
        cpynv tmpl->matctx?bytes-in, len ;
        matctx tmpl, *, opt              ;
brk "2"                                ;
dcl spcptr pos auto                    ;
        addspp pos, tmpl, matctx-len   ;
dcl spc ctx-e bas(pos)                 ;
        dcl dd entry-type char(2) dir  ;
        dcl dd entry-name char(30) dir ;

        sendmsg(entry-name, 30) ; /* the first materialized context entry */
see-you:
        rtx *                   ;

dcl spc matctx-opt-t bas(*)     ;
        dcl dd matctx-opt?info-required char(1) dir ;
        dcl dd matctx-opt?select-criteria char(1) dir ;
        dcl dd matctx-opt?name-len        bin(2) dir  ;
        dcl dd matctx-opt?obj-type        char(1) dir ;
        dcl dd matctx-opt?obj-subtype     char(1) dir ;
        dcl dd matctx-opt?obj-name        char(30) dir ;
        dcl dd matctx-opt?ts              char(8) dir  ;
        dcl dd matctx-opt?asp-num         bin(2) unsgnd dir ;
dcl con matctx-opt-len bin(2) init(46) ;

dcl spc matctx-t bas(*)         ;
        dcl dd matctx?bytes-in bin(4) dir ;
        dcl dd matctx?bytes-out bin(4) dir ;
        dcl dd matctx?obj-type char(2) dir ;
        dcl dd matctx?obj-name char(30) dir ;
        dcl dd matctx?ctx-attr  char(4) dir ;
        dcl dd matctx?rcvy-opt char(4) dir  ;
        dcl dd matctx?spc-size bin(4) dir   ;
        dcl dd matctx?init-spc-val char(1) dir ;
        dcl dd matctx?perf-cls char(4) dir     ;
        dcl dd *               char(7) dir     ;
        dcl dd *               char(16) dir    ;
        dcl sysptr matctx?ag           dir     ;
        /* Extended context attributes (if required)) */
        dcl dd matctx?ext-ctx-attr char(1) dir ;
        dcl dd *                   char(7) dir ;
        dcl dd matctx?cur-ts       char(8) dir ;
        /* Context entries */
dcl con matctx-len bin(2) unsgnd init(96) ;
dcl con matctx-ex-len bin(2) unsgnd init(112) ;

pend                            ;

There is also an RPG example of achieving this job using MATCTX, t031.rpgle, which is provided by another subproject of us, System-builtin Headers and Examples for ILE HLLs.

Now let's have a look at an example Java program that achieves the same job via MI Portal, ListUserProfile.java .

import java.io.IOException;
import com.ibm.as400.access.*;
import u.ByteArray;

public class ListUserProfile {

    public static void main(String[] args) {

        ListUserProfile l = new ListUserProfile();
        l.run();
    }

    private static final String MIPORTAL =
        "/qsys.lib/i5toolkit.lib/miportal.pgm";

    private ProgramCall portal_;

    public void run() {

        byte[] heap_spp = null;
        int len = 0;

        try {
            // allocate 8 bytes of heap storage at the server side
            heap_spp = alloc_heap_storage(8);

            // MATCTX1_H, get number of bytes available
            len = bytes_needed(heap_spp);
            System.out.println("Number of bytes needed to materialize USRPRF names: "
                               + len);

            // reallocate heap storage
            realloc_heap_storage(heap_spp, len);

            // MATCTX1_H, actually materialize usrprf names
            materialize_usrprf(heap_spp, len);

            // report what we get
            read_user_ids(heap_spp, len);

            // free allocated heap storage
            free_heap_storage(heap_spp);

        } catch(Exception e) { e.printStackTrace(); }

    }

    private void read_user_ids(byte[] heap_spp, int len)
        throws Exception
    {
        // read ... returned by MATCTX1
        ProgramParameter[] plist_read = new ProgramParameter[] {
            new ProgramParameter(new byte[] {0x00, 0x08}),  // input, instruction index of READ_FROM_ADDR
            new ProgramParameter(heap_spp),     // input, ID of space pointer
            new ProgramParameter(len),          // output, materialization template
            new ProgramParameter(ByteArray.fromInt32(len)) // input, bytes to copy
        };
        portal_.setParameterList(plist_read);
        if(!portal_.run())
            throw new Exception("read_user_ids");

        byte[] rtn = plist_read[2].getOutputData();
        // debug
        ByteArray.dumpBArray(System.out, rtn, rtn.length);

        ByteArray barr = ByteArray.load(rtn);
        byte[] ctx_attr = new byte[MATCTXOptionTmpl.BASIC_MAT_TMPL_LEN];
        byte[] obj_type = new byte[2];
        barr.readBytes(ctx_attr, MATCTXOptionTmpl.BASIC_MAT_TMPL_LEN);
        String user = "";
        for(int num = 0; barr.position() < len; num++) {
            user = barr.readBytes(obj_type, 2).readEBCDIC37(30);
            System.out.println(num + ": '" + user + "'");
        }
    }

    private void materialize_usrprf(byte[] heap_spp, int len)
        throws Exception
    {
        byte[] mat_tmpl = new ByteArray(8).
            writeInt32(len).  // Number of bytes provided for materialization
            writeInt32(0).  // Number of bytes available for materialization
            toBytes();
        ProgramParameter[] plist_write = new ProgramParameter[] {
            new ProgramParameter(new byte[] {0x00, 0x09}),  // input, instruction index of WRITE_TO_ADDR
            new ProgramParameter(heap_spp),     // input, ID of space pointer
            new ProgramParameter(mat_tmpl),     // input, materialization template
            new ProgramParameter(ByteArray.fromInt32(8)) // input, bytes to write
        };
        portal_.setParameterList(plist_write);
        if(!portal_.run())
            throw new Exception("materialize_usrprf(): call to WRITE_TO_ADDR() failed.");

        byte[] mat_opt = MATCTXOptionTmpl.toBytes(0x08); // object type code = 0x08, USRPRF
        ProgramParameter[] plist_matctx = new ProgramParameter[] {
            new ProgramParameter(new byte[] {0x00, 0x27}),  // input, instruction index of MATCTX1
            new ProgramParameter(heap_spp),  // input, space pointer addressing materialization template
            new ProgramParameter(mat_opt)    // input, materialization options
        };

        portal_.setParameterList(plist_matctx);
        if(!portal_.run())
            throw new Exception("materialize_usrprf(): call to MATCTX1 failed ");
    }

    private void realloc_heap_storage(byte[] heap_spp, int len)
        throws Exception
    {
        ProgramParameter[] plist = new ProgramParameter[] {
            new ProgramParameter(new byte[] {0x00, 0x23}), // instruction index of REALCHSS
            new ProgramParameter(heap_spp),  // ID of space pointer
            new ProgramParameter(ByteArray.fromInt32(len))   // number of bytes to allocate
        };

        // portal_.setParameterList(plist);
        if(!portal_.run())
            throw new Exception("realloc_heap_storage()");
    }

    private byte[] alloc_heap_storage(int len)
        throws Exception
    {
        ProgramParameter[] plist = new ProgramParameter[] {
            new ProgramParameter(new byte[] {0x00, 0x1f}), // instruction index of ALCHSS
            new ProgramParameter(16),  // returned space pointer ID
            new ProgramParameter(ByteArray.fromInt32(0)),  // heap ID
            new ProgramParameter(ByteArray.fromInt32(8))   // number of bytes to allocate
        };

        AS400 i = new AS400();
        portal_ = new ProgramCall(i, MIPORTAL, plist);
        if(!portal_.run())
            throw new Exception("alloc_heap_storage()");

        return plist[1].getOutputData();
    }

    private void free_heap_storage(byte[] heap_spp)
        throws Exception
    {
        ProgramParameter[] plist = new ProgramParameter[] {
            new ProgramParameter(new byte[] {0x00, 0x22}), // instruction index of FREHSS
            new ProgramParameter(heap_spp)                 // space pointer ID
        };

        portal_.setParameterList(plist);
        if(!portal_.run())
            throw new Exception("free_heap_storage()");
    }

    private int bytes_needed(byte[] heap_spp) // @todo should use previously allocated heap storage as TMPL
        throws Exception
    {
        // store materialization template in server-side heap space storage
        byte[] mat_tmpl = new ByteArray(8).
            writeInt32(8).  // Number of bytes provided for materialization
            writeInt32(0).  // Number of bytes available for materialization
            toBytes();
        ProgramParameter[] plist_write = new ProgramParameter[] {
            new ProgramParameter(new byte[] {0x00, 0x09}),  // input, instruction index of WRITE_TO_ADDR
            new ProgramParameter(heap_spp),     // input, ID of space pointer
            new ProgramParameter(mat_tmpl),     // input, materialization template
            new ProgramParameter(ByteArray.fromInt32(8)) // input, bytes to write
        };
        portal_.setParameterList(plist_write);
        if(!portal_.run())
            throw new Exception("bytes_needed(): call to WRITE_TO_ADDR() failed.");

        // call MATCTX1 to get number of bytes needed
        byte[] mat_opt = MATCTXOptionTmpl.toBytes(0x08); // object type code = 0x08, USRPRF
        ProgramParameter[] plist_matctx = new ProgramParameter[] {
            new ProgramParameter(new byte[] {0x00, 0x27}),  // input, instruction index of MATCTX1
            new ProgramParameter(heap_spp),  // input, space pointer addressing materialization template
            new ProgramParameter(mat_opt)    // input, materialization options
        };

        portal_.setParameterList(plist_matctx);
        if(!portal_.run())
            throw new Exception("bytes_needed(): call to MATCTX1 failed ");

        // read mat-tmpl returned by MATCTX1
        ProgramParameter[] plist_read = new ProgramParameter[] {
            new ProgramParameter(new byte[] {0x00, 0x08}),  // input, instruction index of READ_FROM_ADDR
            new ProgramParameter(heap_spp),     // input, ID of space pointer
            new ProgramParameter(8),            // output, materialization template
            new ProgramParameter(ByteArray.fromInt32(8)) // input, bytes to copy
        };
        portal_.setParameterList(plist_read);
        if(!portal_.run())
            throw new Exception("bytes_needed(): call to WRITE_TO_ADDR() failed.");

        byte[] rtn = plist_read[2].getOutputData();
        int bytes_available = ByteArray.load(rtn, 4, 4).readInt32();
        return bytes_available;
    }

} // class ListUserProfile

class MATCTXOptionTmpl {

    public static final int OPTION_TEMPLATE_LENGTH = 46;
    public static final int BASIC_MAT_TMPL_LEN = 96;
    public static final int EXTENDED_MAT_TMPL_LEN = 112;

    public static
        byte[]
        toBytes(int objectTypeCode)
        throws IOException
    {
        ByteArray barr = new ByteArray(OPTION_TEMPLATE_LENGTH);
        barr.writeBytes(0x05, 1)   // Do NOT validate system pointers; no extended template
                                   // returns only symbolic IDs
            .writeBytes(0x01, 1)   // Materialize the machine context; select by 1-byte object type code
            .writeInt16(0)         // UBin(2) length of object-name; not used
            .writeBytes(objectTypeCode, 1)   // 1-byte object type code, hex 08 (USRPRF)
            .writeBytes(0x00, 1)   // 1-byte object subtype code; not used
            .writeBytes(0x00, 30)  // 30-byte object name; not used
            .writeBytes(0x00, 8)   // 8-byte timestamp
            .writeInt16(0);        // UBin(2) independent ASP number; not used

        return barr.toBytes();
    }

}

Support This Project
Generated on Tue Sep 27 08:34:40 2011 for i5/OS Programmer's Toolkit: MI Portal by  doxygen 1.5.9