MAINFRAME > Administrator > IMS

Implementing IMS Synchronous Program-to-Program Switches Using DB2 for z/OS


Since the beginning of IMS, more than 40 years ago, the program-to-program switch has been implemented and used by most installations in their business logic.

Most experienced users know how to implement a program-to-program switch, which is shown in Figure 1:

  1. An application program retrieves the message by using the Get Unique (GU) call of the IMS Data Language/I (DL/I) API and prepares the switch using the CHNG call of the DL/I API with a new destination (another transaction)
  2. The application program sends the message to the destination using the ISRT call of the DL/I API. This new destination could be in the same IMS or in a remote IMS coupled by the IMS Multiple Systems Coupling (MSC) feature.
  3. The reply to the client can be returned by the initial application or by the one switched to by inserting a message on the I/O program control block (PCB) using the ISRT call of the DL/I API, depending on the business logic.

Unfortunately, this model cannot be used for business logic that needs synchronous execution of the two applications. Furthermore, the two applications aren’t in the same logical unit of work (LUW). So, the initial application isn’t aware if the switched application fails.

Beginning With Synchronous Call

In IMS V10, a new call was introduced in the DL/I API: ICAL. It was a kind of revolution for IMS, since it was the first time an IMS application could synchronously call an external service running somewhere “out of the box.” The ICAL call is a strange API call, from the point of view of IMS. Its messages do not pass through the normal IMS messages queues, are not recoverable, can be of any size, and don’t have the traditional LLZZ prefix. The ICAL call implements a timeout feature and generates very specific log records. Of course, the ICAL call needs the Open Transaction Manager Access (OTMA) function of IMS and cannot pass through any of the SNA protocols.

But, at least until IMS V13, the cobbler's children will go barefoot. We can send ICAL messages to external services but not to another IMS application.

Synchronously Calling an IMS Application

Fortunately, our friends from DB2 (beginning with DB2 V8) had a pretty good idea: encapsulating in a DB2 stored procedure, which is, by definition, the model of a synchronous call, the code to invoke IMS transactions and commands easily, without maintaining any connections to IMS. These two DB2 stored procedures for IMS are:

  • DSNAIMS for single-segment input IMS transactions
  • DSNAIMS2 for multi-segment input IMS transactions

Both require DB2 with the Resource Recovery Services Attachment Facility (RRSAF) enabled and IMS V7 or later with the OTMA Callable Interface (C/I) enabled. To use a two-phase commit process, IMS V9 or later is required with z/OS RRS active.

IMS provides a stand-alone program, DFSYSVI0, for initializing the OTMA C/I. It must be run after the z/OS IPL to initialize the OTMA C/I. You must add an entry in the z/OS program properties table (PPT) for the OTMA C/I initialization program. The steps for doing this are:

1. Edit the SCHEDxx member of the SYS1.PARMLIB data set to add the following entry to the SCHEDxx member:

PPT PGMNAME(DFSYSVI0)	/* PROGRAM NAME = DFSYSVI0 */
CANCEL 			/* PROGRAM CAN BE CANCELED */
KEY(7)			/* PROTECT KEY ASSIGNED IS 7 */
SWAP				/* PROGRAM IS SWAPPABLE */
NOPRIV			/* PROGRAM IS NOT PRIVILEGED */
DSI				/* REQUIRES DATA SET INTEGRITY */
PASS				/* CANNOT BYPASS PASSWORD PROTECTION */
SYST				/* PROGRAM IS A SYSTEM TASK */
AFF(NONE)			/* NO CPU AFFINITY */
NOPREF 			/* NO PREFERRED STORAGE FRAMES */

2. To make the SCHEDxx changes effective, take one of the following actions:

  • Re-IPL the z/OS system, or
  • Issue the z/OS SET SCH=xx command.

You could then start the following procedure for running DFSYSVI0:

//OTMACI PROC
//IEFPROC EXEC PGM=DFSYSVI0,REGION=3M
//STEPLIB DD DISP=SHR,DSN= //SYSPRINT DD SYSOUT=* //SYSUDUMP DD SYSOUT=* //* 

The following example (Code Sample 1) shows a very trivial IMS transaction, HELLO, written in REXX, which returns some general information about the running IMS.

/* REXX                                                              */
smfid=mvsvar('sysname')                                                
SUBCOM 'REXXIMS'                                                       
If RC <> 0 Then Exit 999                                               
Address REXXIMS                                                        
'IMSRXTRC 0'                                                           
                                                                       
'GU IOPCB SEG'                                                         
Status = REXXIMS('STATUS')                                             
                                                                       
Func = "ENVIRON"      /* Sub-Function Value */                              
"SET SUBFUNC Func"    /* Set the value */                                 
"INQY IOPCB EnviData" /* Make the DL/I Call */                         
IMS_Identifier   = Substr(EnviData,1,8)                                
IMS_Release      = c2x(Substr(EnviData,9,4))                           
Ctl_Region_type  = Substr(EnviData,13,8)                               
Appl_Region_type = Substr(EnviData,21,8)                               
Region_id        = c2x(Substr(EnviData,29,4))                          
User_id          = strip(Substr(EnviData,57,8))                        
m = 'HELLO' User_id','                                                 
Call SayIt left(m,72)                                                  
m =   'You are on' strip(IMS_Identifier) 'which is'                    
m = m 'an IMS Version' substr(IMS_Release,5,2)                         
m = m 'running on' smfid                                               
Call SayIt left(m,72)                                                   
m = 'The Control Region type is' Ctl_Region_type                        
Call SayIt left(m,72)                                                   
m = 'Today, we are' date() 'and it is' time()                           
Call SayIt left(m,72)                                                   
                                                                        
Exit 0                                                                  
                                                                        
SayIt: Procedure                                                        
   Parse Arg Msg                                                        
   address REXXIMS 'ISRT IOPCB MSG'                                     
                                                                        
Return

When you type HELLO on your 3270 IMS session, you receive the following reply:

HELLO ,
You are on TP3 which is an IMS Version 11 running on SYST
The Control Region type is DB/DC
Today, we are 15 Apr 2013 and it is 13:39:56

To call this transaction synchronously, we use a REXX program that implements the DSNAIMS stored procedure, as shown in Code Sample 2. Of course, you could implement this call like any other SQL call in an IMS transaction or in any environment (batch, for example) in z/OS and even out of the z/OS box, anywhere you have a DB2 client.

/* rexx                                                              */
                                                                        
DB2_Local='D2TA'         /* the local DB2                            */ 
DB2_Ims  ='D2TA'         /* the DB2 where the StoredProc runs        */ 
xcf_group_name='IMS3HWS' /* the XCF group name of the IMS            */ 
                         /* running the tran                         */ 
xcf_ims_name='IMS3'      /* the XCF group member name of the IMS     */ 
                         /* running the tran                         */ 
                                                                        
"subcom dsnrexx"                                                        
if rc then s_rc = rxsubcom('add','dsnrexx','dsnrexx')                   
                                                                        
address dsnrexx "connect " DB2_Local                                 
                                                                        
if sqlcode <> 0 then                                                    
   do                                                                   
     say 'Error while connecting to' DB2_Local 'sqlcode='sqlcode        
     exit 8                                                             
   end                                                                

/* preparing DSNAIMS parameters */
dsnaims_function='SENDRECV' 
dsnaims_2pc=''                                                          
racf_userid=sysvar("sysuid")                                            
racf_groupid=''                                                         
ims_lterm=''                                                            
ims_modname=''                                                          
ims_tran_name='HELLO'                                                   
ims_data_in=' '                                                         
ims_data_out=left(' ',1024,' ')                                         
otma_tpipe_name=''                                                      
otma_dru_name=''                                                        
otma_user_data_in=''                                                    
otma_user_data_out=''                                                   
status_message=left(' ',120,' ')                                        
return_code=0                                                           
                                                                        
/* We use below the three parts name of the stored procedure */         
sqlstmt = "execsql call " DB2_Ims!!".sysproc.dsnaims ",                 
          "(:dsnaims_function       ,",                                 
          " :dsnaims_2pc            ,",                                 
          " :xcf_group_name         ,",                                 
          " :xcf_ims_name           ,",                                 
          " :racf_userid            ,", 
          " :ims_lterm              ,",                                 
          " :ims_modname            ,",                                 
          " :ims_tran_name          ,",                                 
          " :ims_data_in            ,",                                 
          " :ims_data_out           ,",                                 
          " :otma_tpipe_name        ,",                                 
          " :otma_dru_name          ,",                                 
          " :otma_user_data_in      ,",                                 
          " :otma_user_data_out     ,",                                 
          " :status_message         ,",                                 
          " :return_code)            "                                  
                                                                   
address dsnrexx sqlstmt                                             
    
if sqlcode <> 0 then                                                
              do                                                        
                say 'DSNAIMS call error '                               
                say 'sqlcode  =' sqlcode                                
                say 'sqlerrmc =' sqlerrmc                               
                say 'sql statement follows:'                            
                say sqlstmt                                             
                exit 8 
	      end

if return_code <> 0 then say 'DSNAIMS status message =' status_message 
 
/* Only for formatting the reply   */                            
data=strip(ims_data_out)                                           
do i=1 to length(data) by 72                                       
   say substr(data,i,72)                                           
end                                                                
                                                                    
address dsnrexx "disconnect "                                        
                                                                        
exit 0

Edmond Torikian is an IMS expert consultant, currently working for Allianz in France. He has more than 25 years of experience in mainframe technologies, database architectures and performance analysis.


comments powered by Disqus

Advertisement

Advertisement

2019 Solutions Edition

A Comprehensive Online Buyer's Guide to Solutions, Services and Education.

Bringing IMS and SOA Together With IMS Connect

New requirements for IMS Connect functionality could make implementing an SOA environment with IMS easier and more flexible.

Celebrating 40 Successful Years

IMS version 10 supports synchronous and asynchronous callout

IBM Systems Magazine Subscribe Box Read Now Link Subscribe Now Link iPad App Google Play Store
Mainframe News Sign Up Today! Past News Letters