+ All Categories
Home > Documents > Open Access for RPG - MowYourLawn · Abstract Open Access for RPG (OAR) has now been out for more...

Open Access for RPG - MowYourLawn · Abstract Open Access for RPG (OAR) has now been out for more...

Date post: 27-Jul-2018
Category:
Upload: dinhnga
View: 214 times
Download: 0 times
Share this document with a friend
24
OAR Open Access for RPG by Aaron Bartell of KrengelTech [email protected] Copyright Aaron Bartell 2011
Transcript

OAROpen Access for RPG

by Aaron Bartellof KrengelTech

[email protected] Aaron Bartell 2011

AbstractOpen Access for RPG (OAR) has now been out for more

than a couple years and is arguably the most highly praised and criticized feature RPG has ever had.

Learn more about what OAR can do for you and the various roles and scenarios it can be of benefit. Learn how you can use OAR to modernize your existing applications and see it in action with some free and open source tooling that uses OAR to communicate with the browser.

• Formal name: Rational Open Access: RPG Edition• Community references: OAR, RPG Open Access, Open Access for RPG

• IBM’s definition...• “A full-featured version of the limited support provided by RPG SPECIAL

files that provides a way for RPG programmers to use the simple and well-understood RPG I/O model to access new devices and resources that are not directly supported by RPG.”

• My definition...• Opens up the traditional RPG opcodes (i.e. CHAIN, READ, WRITE,

EXFMT) and allows the RPG programmer to intercept any and all communications for the purposes of hiding complexities - complexities like “talking” to the browser.

• OAR is for everyone, not just vendors!

What is OAR?

More OAR info. . .First, learn about pricing: http://bit.ly/nnm1Yz Pricing as of 2012-01-01 will be as follows:

P05 - $515P10 - $1030P20 - $2580P30 - $5150P40 - $5150P50 - $5150P60 - $5150

Formal documentation: http://bit.ly/g7yd4z

Talk about it at the RPG Cafe: http://ibm.co/oljMrs

X Open Access for RPG is now FREE!

Requirements

IBM i 6.1 IBM Rational Development Studio for i V6.1 (5761-WDS) with applicable

PTFs

or

RPG runtime V6.1 (5761-SS1) with applicable PTFs

IBM i V7.1 IBM Rational Development Studio for i V7.1 (5770-WDS) with applicable

PTFs

or

RPG runtime V7.1 (5770-SS1) with applicable PTFs.

The PartsAn Open Access app has three parts . . .

An RPG program that defines an Open Access file. This is the program that will have your traditional opcodes being executed against the file (i.e. CHAIN, READ, WRITE, etc).

The HANDLER program that overrides the traditional IBM i RPG compiler functionality.

The F-spec defined file that the opcodes are being executed against.

MYPGM

FGENERICPF if a e disk handler('HNDPGM_BUF') usropn

HNDPGM_BUFGENERICPF

IBMi DB2

WRITE

NO

YES

1

2

3

1

2

3

GENERICPF

A R GENERICR TEXT('Generic DB2 table') A CHAR1 10A A PCKDEC1 15P 2 A DATE1 L A TMSTMP1 Z

This is only necessary at compile time if you are only using it for it’s structure but not to store data.

MYPGM H dftactgrp(*no) Option(*DebugIO)

FGENERICPF if a e disk handler('HNDPGM_BUF') usropn /free

open GENERICPF; read GENERICR; exsr dsplyIO;

char1 = 'Updated ' + char1; pckDec1 += 100; date1 += %Years(100); tmStmp1 += %Years(100); write GENERICR;

close GENERICPF;

*inlr = *on;

//--------------------------- // Output the current record //--------------------------- begsr dsplyIO; dsply ('char1: ' + char1); dsply ('pckDec1: ' + %char(pckDec1)); dsply ('date: ' + %char(date1)); dsply ('tmpStmp1: ' + %char(tmStmp1)); endsr; /end-free

Tell the RPG compiler that we want a custom OAR handler to process all GENERICPF interactions.

HNDPGM_BUF

H dftactgrp(*no)

/copy QOAR/qrpglesrc,qrnopenacc

D HNDPGM pr extpgm('HNDPGM_BUF') D info likeds(QrnOpenAccess_T) D HNDPGM pi D info likeds(QrnOpenAccess_T)

D buffer e ds based(pbuffer) D extname('*LIBL/GENERICPF': *ALL) /free

Delivered with OAR product

This allows us to more easily parse through the columns in GENERICPF, but obviously ties us directly to this specific physical file.

QrnOpenAccess_TD QrnOperation_OPEN...

D C 1

D QrnFunctionKey_03... D C 3

D QrnDatatype_Decimal... D C 8

D QrnRecordLevel_T... D DS QUALIFIED TEMPLATE D record 10A D level 13A

D QrnNameValue_T DS QUALIFIED TEMPLATE D externalName 10A D dataType 3U 0 D numericDefinedLen 3U 0 D decimals 3U 0 D dtzFormat 3U 0 D dtSeparator 1A D input N D output N D isNullCapable N D hasNullValue N ... and MANY more ...

Constants for each operation

Constants for the key pressed

Data types for name-value information

Name-value pair data structure that gives A LOT of information about the device (i.e. DB2 table, columns) that is being acted upon.

HNDPGM_BUF (2) select;

when info.rpgOperation = QrnOperation_OPEN; dsply ('---- Operation: OPEN ----'); info.useNamesValues = *Off;

when info.rpgOperation = QrnOperation_WRITE; dsply ('---- Operation: WRITE ----'); pbuffer = info.outputBuffer; exsr dsplyIO;

when info.rpgOperation = QrnOperation_CLOSE; dsply ('---- Operation: CLOSE ----');

when info.rpgOperation = QrnOperation_READ; dsply ('---- Operation: READ ----'); pbuffer = info.inputBuffer; char1 = 'Furry Java Llama'; pckdec1 = 2.22; date1 = d'2003-03-03'; tmstmp1 = z'2004-04-14-04.40.00.000000'; Other; dsply ('---- Operation: UNHANDLED OPERATION ----'); endsl;

begsr dsplyIO; dsply ('char1: ' + char1); dsply ('pckDec1: ' + %char(pckDec1)); dsply ('date: ' + %char(date1)); dsply ('tmpStmp1: ' + %char(tmStmp1));endsr;

Check for operation and act accordingly.

Obtain buffer from RPG compiler and apply to local buffer which is mapped to a data structure reference of GENERICPF.

Declares that we are NOT using the name-value pair approach and instead the I/O buffer.

HNDPGM_BUF (3)

CALL MYPGM DSPLY ---- Operation: OPEN ---- DSPLY Supplying Input data DSPLY char1: Furry Java DSPLY pckDec1: 2.22 DSPLY date: 2003-03-03 DSPLY tmpStmp1: 2004-04-14-04.40.00.000000DSPLY ---- Operation: WRITE ---- DSPLY char1: Updated Fu DSPLY pckDec1: 102.22 DSPLY date: 2103-03-03 DSPLY tmpStmp1: 2104-04-14-04.40.00.000000DSPLY ---- Operation: CLOSE ----

Job log after running MYPGM with HNDPGM_BUF as the HANDLER program.

HNDPGM_NV (using name-value pair)

FGENERICPF if a e disk handler('HNDPGM_NV') usropn

. . .

H dftactgrp(*no) /copy qoar/qrpglesrc,qrnopenacc D HNDPGM pr extpgm('HNDPGM_NV') D info likeds(QrnOpenAccess_T) D HNDPGM pi D info likeds(QrnOpenAccess_T)

D fields ds likeds(QrnNamesValues_T) D based(pNVInput)

D value s 40a based(pValue) D i s 5i 0 D dsplyLen s 5i 0

. . .

Change MYPGM to have a new HANDLER value of HNDPGM_NV.

}

This data structure lists the names, types, and values of each subfield in the record and is the only change in the D-specs when transitioning from HNDPGM_BUF to HNDPGM_NV.

HNDPGM_NV

MYPGM

HNDPGM_NV (2) select;

when info.rpgOperation = QrnOperation_OPEN; dsply ('---- Operation: OPEN ----'); info.useNamesValues = *On; s when info.rpgOperation = QrnOperation_WRITE; dsply ('---- Operation: WRITE ----'); pNVInput = info.namesValues; for i = 1 to fields.num; pvalue = fields.field(i).value; if fields.field(i).valueLenBytes < 25; dsplyLen = fields.field(i).valueLenBytes; else; dsplyLen = 25; endif; dsply (%trim(fields.field(i).externalName) + ' : ' + %subst(value: 1: dsplyLen)); endfor;

when info.rpgOperation = QrnOperation_CLOSE; dsply ('---- Operation: CLOSE ----');

. . .

Ask for names/values on subsequent IO

Dynamically iterate through the fields and obtain the value and name to display in the job log.

Grab the pointer and apply it to our own variable.

HNDPGM_NV (3) . . .

when info.rpgOperation = QrnOperation_READ; dsply 'Supplying Input data'; pNvInput = info.namesValues; for i = 1 to fields.num; pvalue = fields.field(i).value; select; when fields.field(i).externalName = 'CHAR1'; fields.field(i).valueLenBytes = 16; %subst(value: 1: 16) = 'Furry Java Llama'; when fields.field(i).externalName = 'PCKDEC1'; fields.field(i).valueLenBytes = 4; %subst(value: 1: 4) = '2.22'; when fields.field(i).externalName = 'DATE1'; fields.field(i).valueLenBytes = 10; %subst(value: 1: 10) = '2003-03-03'; when fields.field(i).externalName = 'TMSTMP1'; fields.field(i).valueLenBytes = 26; %subst(value: 1: 26) = '2004-04-14-04.40.00.000000'; other; dsply ('Unknown field: ' + fields.field(i).externalName); endsl; endfor; other; dsply ('---- Operation: UNHANDLED OPERATION ----'); endsl;

info.rpgstatus = 0;

Set up access to name-value information

Set the RPG status to zero to signify this action was successful

Determine which field we are working with and supply a value.

READ operation

HNDPGM_NV (4)

CALL MYPGM DSPLY ---- Operation: OPEN ---- DSPLY Supplying Input data DSPLY char1: Furry Java DSPLY pckDec1: 2.22 DSPLY date: 2003-03-03 DSPLY tmpStmp1: 2004-04-14-04.40.00.000000DSPLY ---- Operation: WRITE ---- DSPLY CHAR1-Updated Fu DSPLY PCKDEC1-102.22 DSPLY DATE1-2103-03-03 DSPLY TMSTMP1-2104-04-14-04.40.00.00000 DSPLY ---- Operation: CLOSE ----

Job log after running MYPGM with HNDPGM_NV as the HANDLER program.

OAR + OpenRPGUI + ExtJSDisplay a graphical window in the browser using ExtJS.

When the user selects GO, a request will be made to an OAR program through Apache on the IBMi.

The OAR handler will implement OpenRPGUI* APIs to READ and WRITE to the browser.

*www.OpenRPGUI.com

oaroru.html<html>

<head> <title>Open Access RPG (OAR) Meets OpenRPGUI (ORU)</title> <link rel='stylesheet' type='text/css' href='/ext-all.css' /> <script type='text/javascript' src='/ext-base.js'></script> <script type='text/javascript' src='/ext-all.js'></script> <script type="text/javascript"> Ext.onReady(function(){ var pnl1 = new Ext.FormPanel({ id:'pnl1', title:'Open Access RPG meets OpenRPGUI', width:300,padding:'10px', renderTo:Ext.getBody(), items:[{ fieldLabel:'Type Something', id:'FLD1',xtype:'textfield' },{ fieldLabel:'You Said', id:'YOUSAID',xtype:'label' }], buttons:[{text:'GO',handler:btnHandler}] });

function btnHandler(button, event){ // Code omitted for brevity } }); </script> </head> <body style='margin: 70px 70px 70px 70px;'></body></html>

Note this input field has a name/id of “FLD1”

Note this output field has a name/id of “YOUSAID”

MYPGMORU.rpgle H dftactgrp(*no)

FMYDSP cf e workstn handler('HNDPGMORU':sharedIO)

D sharedIO ds qualified D name 30a varying D value 1024a varying

D gFld1 s 1024a varying /free

sharedIO.name = 'FLD1'; read MYDSPR; gFld1 = sharedIO.value;

sharedIO.name = 'YOUSAID'; sharedIO.value = gFld1; write MYDSPR;

*inlr = *on;

/end-free

}

Specify the name of inbound field we want to obtain.

Save the value in a local field

Occupy the name and value subfields of the sharedIO data structure and then WRITE the record, which subsequently writes to the browser.

The sharedIO data structure is the “comms area” between this program and the handler. You can create ANY data structure and subfields that you want.

HNDPGMORU.rpgle H dftactgrp(*no) bnddir('ORUBND')

/copy qoar/qrpglesrc,qrnopenacc /copy qrpglecpy,http

D sharedIO ds qualified D based(pSharedIO) D name 30a varying D value 1024a varying

D HNDPGMORU pr extpgm('HNDPGMORU') D io likeds(QrnOpenAccess_T) D HNDPGMORU pi D io likeds(QrnOpenAccess_T)

D gStdIn s 1024a varying D gInitRead s n inz(*on) D gFirstWrite s n inz(*off) /free

Same sharedIO data structure needs to also exist in the handler program.

OpenRPGUI binding directory and copybook

Misc fields to be used to retain state for this full loop transaction to the server.

HNDPGMORU.rpgle (2)

pSharedIO = io.userArea;

select; when io.rpgOperation = QrnOperation_READ; if gInitRead; gStdIn = http_inStr(); gInitRead = *off; endif; sharedIO.value = http_getCgiVal(sharedIO.name: gStdIn); gFirstWrite = *on; when io.rpgOperation = QrnOperation_WRITE; if gFirstWrite; http_outStr('Content-Type: text/plain' + x'1515'); gFirstWrite = *off; endif; http_outStr( '{' + sharedIO.name + ':' + '''' + sharedIO.value + '''}' ); gInitRead = *on; other; dsply ('---- Operation: UNHANDLED OPERATION ----'); endsl;

return;

Read from “standard input” and store for all subsequent READ operations, but only do this once. Then go to sharedIO.name to learn of the field to be read.

Apply what the RPG compiler received from MYPGMORU to our sharedIO data structure

If this is the first WRITE back to the browser then make sure the HTTP headers are sent.

Write out the name-value pair in JSON format. ex:{YOUSAID:‘asdf’}

Who is using OAR?

ProfoundLogic - http://profoundui.com/ - http://www.profoundlogic.com/docs/display/PUI/Introduction - http://www.profoundlogic.com/docs/display/PUI/Creating+Your+First+ProfoundUI+App - http://www.profoundlogic.com/docs/display/PUI/Walkthroughs

TEMBO Technology - www.tembotechlab.com and www.adsero-optima.com

looksoftware - www.looksoftware.com- www.looksoftware.com/Portals/0/looksoftware/repository/pdf/rpg_oa_faq.pdf

OpenRPGUI - http://OpenRPGUI.com

Articles

Decoupling RPG database IO using Rational Open Access: RPG Edition http://ibm.co/q3VFOo

You Can Handle RPG OA http://bit.ly/oL0gIY

Getting a Handle on RPG’s Open Access http://bit.ly/r79QEa

Rowing with Your OAR http://bit.ly/o0PELQ

RJS Adopts OAR to Simplify Remote Database Access http://bit.ly/reu2lQ

Aaron Bartell [email protected] developer of RPG-XML Suite (www.rpg-xml.com)‏

and owner of www.MowYourLawn.com and check out his latest effort at www.SoftwareSavesLives.com

We have reached the end!

.com/aaronbartell


Recommended