180 likes | 308 Views
EGL and IMS Support. A short, high-level introduction to the language and tooling features For more information, please contact Jon Sayles: jsayles@us.ibm.com. From 10,000 Feet. Support for: IMS TM Formatted and un-formatted 3270 screens Alternate IO-PCB IMS BMP
E N D
EGL and IMS Support A short, high-level introduction to the language and tooling features For more information, please contact Jon Sayles: jsayles@us.ibm.com
From 10,000 Feet Support for: • IMS TM • Formatted and un-formatted 3270 screens • Alternate IO-PCB • IMS BMP • zOS – IMS Batch (DL/I programs) • DL/I Database • All databases and access methods supported • HDAM/HIDAM • Secondary Index • Logical Relationships • GSAM • Complete DL/I language support • Different levels of abstraction – use of consistent vocabulary • Ability to support custom/complex requirements through #dli{ • Special records that provide abstracted and simplified coding – AND learning IMS
WAS - AIX Web Services EGL - IMS Run-Time Architecture DL/I Database zSeries – IMS/VS – DB2 MSG Queue EGL Catcher Program EGL COBOLGEN Program
From 10,000 Feet – Development Architecture Support for: • TUI/MFS Interface – tooling and form editors available to produce • Pagehandlers – generated to Java • Services – generated to Java • IMS Programs – generated to COBOL • Buildfile entries for lots of things • Build Server – COBUCL • Call: ELAISVN • EGL “catcher program” that is called by IMS Connect Transaction: • ELAISVN Is defined to AIB – with aliases for all user program PSB • Scans the iopcb message queue for requests for said PSBs • Gets scheduled • Handles data mapping and Linkage Parms: • Unformatted 3270 data streams (IMS Message data, passed to your called program) • Invokes custom IMS/VS programs (your generated EGL code – or Native COBOL !) • Handles passing returned data/parms to caller client programs • Pages/Services/MFS
DLISegment Record • Record subtypes are used to associate meta data with a data type definition Record CustomerRecordPart type DLISegment { segmentName="STSCCST", keyItem="customerNo" } 10 customerNo char(6) { dliFieldName = "STQCCNO" }; //key 10 customerName char(25) { dliFieldName = "STUCCNM" }; 10 customerAddr1 char(25){ dliFieldName = "STQCCA1" }; 10 customerAddr2 char(25){ dliFieldName = "STQCCA2" }; 10 customerAddr3 char(25){ dliFieldName = "STQCCA3" }; end You define records to match segments in DL/I database The above record provides developers with the following kinds of coding/productivity constructs: Move in_cust_no to customerNo; Get CustomerRecord;
PSBRecord EGL provides predefined records for the I/O PCB, alternate PCB, database PCB, and GSAM PCB structures. Record CustomerPSB type PSBRecord { defaultPSBName="STBICLG" } // three PCBs required for CBLTDLI on IMS { @PCB { pcbType = TP } }; elaalt ALT_PCBRecord { @PCB { pcbType = TP } }; elaexp ALT_PCBRecord { @PCB { pcbType = TP } }; // database PCB defining four segment levels customerPCB DB_PCBRecord { @PCB { pcbType = DB, pcbName = "STDCDBL", hierarchy = [ @Relationship { segmentRecord = "CustomerRecordPart" }, @Relationship { segmentRecord = "LocationRecordPart", parentRecord = "CustomerRecordPart" }, @Relationship { segmentRecord = "OrderRecordPart", parentRecord = "LocationRecordPart" }, @Relationship { segmentRecord = "ItemRecordPart", parentRecord = "OrderRecordPart" }, @Relationship { segmentRecord = "CreditRecordPart", parentRecord = "CustomerRecordPart" }, @Relationship { segmentRecord = "HistoryRecordPart", parentRecord = "CustomerRecordPart" } ]}};
DL/I Data Access Calls EGL provides different layers of abstraction for your DL/I programming Function FLSCOMP_MAIN() // 1. Implicit DL/I -- retrieves the segment based on the key and DLISegent properties getSTORESEG; // 2. Explicit DL/I -- with specific SSA for just the root segment – over-rides DLISegment // use : to indicate a host variable (not a DLI term), but like SQL get STORESEG usingPCB psb.STORE_dbPCB with #dli{GU STORESEG(STORE# = :inputStore & COMPFLAG = "Y") } ; //3. Custom DL/I -- multiple segments and the D (path call) command code get COURSE, STUDENT usingPCB psb.COURSE_dbPCB with #dli{ GU COURSE*D (COURSE# = :COURSE.COURSE#) OFFERING (LOCATION = :OFFERING.LOCATION & CITY = :MYDBPRG_WS.MYCITY) STUDENT (EMPNO = :STUDENT.EMPNO) } ; Note for the above 3 types of IMS db access EGL parses the IMS calls, ensuring that all operands are space-filled to the appropriate length, upper-case, etc. You can also code native DL/I using DLILIB (system function library)
DL/I Implicit and Explicit Calls Calls generated from: 1. DLISegment record, 2. Your coding Function FLSCOMP_MAIN() // 1. Implicit DL/I -- retrieves the segment based on the key and DLISegent properties CustRec CustomerRecordPart; customerNo = inputCustNo; //Value obtained from Service or web page getCustRec; // 2. Explicit DL/I - over-rides DLISegment get CustRec usingPCB psb.STORE_dbPCB with #dli{ GU CustRec (customerName >= :inputName & customerAddr3 = :addr1) } ;
#dli directive Lets you modify the default DL/I calls that EGL generates from I/O keywords. get myLocation with #dli{ GU STSCCST (STQCCNO = :myCustomer.customerNo) STSCLOC (STQCLNO = :myLocation.locationNo) }; Can use this directive when: - Need to add DL/I command code - Retrieve a segment not based on key-field value - Doing “skip sequential” processing
DLILIB – Option for customized DL/I Calls • DLILib.AIBTDLI() uses the AIBTDLI interface to invoke a DL/I function directly. DLILib.AIBTDLI()( funcCHAR(4)in, pcbNameSTRINGinparms...ANY) • Example: Record CustomerPSBRecordPart type PSBRecord { defaultPSBName="STBICLG" } // database PCB customerPCB DB_PCBRecord { @PCB { pcbType = DB, pcbName = "STDCDBL", hierarchy = [ @Relationship { segmentRecord = "CustomerRecordPart" }, ...]}}; end mypsb CustomerPSBRecordPart; //variable definition of PSB • Define I/O area…define and format your SSAs. Issue the DL/I FLD call as follows: DLILib.AIBTDLI("FLD", "STDCDBL", myIOArea, mySSA1, ... mySSAn); if (CustomerRec not handleIOError) // do error processing end
DL/I Program - Properties ProgramFLSCOMPtype basicProgram (inputStore bigint, outputCompFlag char(1), outputDate char(8)) { // whatever other properties you generally use @DLI { psb = "psb", // name of variable that defines the psbRecord callInterface = DLICallInterfaceKind.AIBTDLI //, this is the default; // be sure IMS PSB is set up for AIBTDLI // if not, can specify separate CBLTDLI pcbs // // You can pass the entire psb on a call into this program // psbParm = "psbData" // // Or, you pass individual pcbs on a call into this program // pcbParms = ["iopcb", "ELAALT", "", "STORE_dbPCB", "", ""] } }
DL/I Error Handling • Can “roll your own” – or leverage built-in coding standards: if (myRec is noRecordFound) …
Examples – Searching within a parent segment • Retrieve the items for a particular order. • You can use the following to retrieve the order: get myOrder with #dli { GU STSCCST (STQCCNO = :myCustomer.customerNo) STSCLOC (STQCLNO = :myLocation.locationNo) STSOCORD (STQCODN = :myOrder.orderDateno) }; Use the following to retrieve the line segments within the order: get next inParent myItem; while (myItem not noRecordFound) // process the current item get next
Examples – Searching with a non-key field Search on the creditBalance field (STFCSBL) in the credit segment (STSCSTA). 1. Define a variable of type decimal(12,2) (for example, ″targetBalance″) 2. Write a get next statement for the myCrStatus record. 3. Add a #dli directive to the line, modifying the default code. 4. Add a qualified SSA that looks for a segment where the amount in the creditBalance field is greater than targetBalance. 5. Include a path command code (*D) to retrieve the customer segment (STSCCST) that corresponds to the credit segment. TargetBalance decimal(12,2); targetBalance = 10,000.00; //or any input variable value get next myCustomer,myCrStatus with #dli{ GU STSCCST*D STSCSTA (STFCSBL >= :targetBalance) };
Examples – Path calls and implicit SSAs EGL I/O statement with dependent segments get myCustomer, myLocation, myOrder; //Path get //This statement generates the following DL/I pseudocode: GU STSCCST*D (STQCCNO = :myCustomer.customerNo) STSCLOC*D (STQCLNO = :myLocation.locationNo) STPCORD (STQCDDN = :myOrder.orderDateNo) Note that if you use the D command code on a get...forUpdate statement, the subsequent replace statement affects every segment retrieved. You can prevent replacement of a selected segment by specifying an explicit N command code in the SSA for the replace keyword, as in the following example, which replaces only the location and order segments: get myCustomer, myLocation, myOrder forUpdate; //Path get replace myOrder with #dli{ REPL STSCCST*N STSCLOC*N STPCORD };
Examples – Read all database segments EGL I/O statement with dependent segments myHistory HistoryRecord; redefCustomer CustomerRecord {redefines=myHistory}; redefLocation LocationRecord {redefines=myHistory}; ... //read next segment, whatever type it is, into history record while (myHistory not EOF) get next myHistory with #dli{ GN }; //so what type was it? case (DLIVar.segmentName) when "STSCCST" // it was a customer when "STSCLOC" // it was a location ... end end