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.
Note that, all Java examples in this section can be run either at an IBM i server locally or from a remote PC.
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(); } } }
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(); } } }
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
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(); } } }
/* 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(); } }