DSNACICS. Why use DSNACICS? calling DSNACICS through REST API – A user experience
DSNACICS is a useful IBM supplied procedure for Db2. What does DSNACICS do? It allows one to invoke a CICS server program.
- To be clear. you don’t invoke a CICS transaction. You invoke a CICS program!
The official IBM reference: https://www.ibm.com/docs/en/db2-for-zos/12?topic=db2-dsnacics
- See end of this blog for a few interesting caveats on using DSNACICS
Why would one use a DSNACICS? Let us say you have a distributed application with the occasional need for some information that is easily available via a CICS program. Examples include:
- A VSAM file is attached to a CICS region that maintains the data values, and you want to look up a value from the VSAM while it is attached to the CICS region. Then you find (or make) a simple CICS program that read that data and call that CICS program through DSNACICS.
- Perhaps there is some existing CICS program that performs some complicated function or logic that you want to invoke from a distributed application
- Other reasons?
You probably would not use DSNACICS to call a CICS program with complicated input parameters or complicated data that needs to be passed into the COMMAREA. Well… you could use DSNACICS to call that type of program… but it might be a challenge for the distributed application to prepare the COMMAREA.
You probably would not use DSNACICS to invoke a CICS program get Db2 data. Why would you do that? Just query the table yourself in your program (or make a little Db2 procedure to get the data). No need to add the overhead of DSNACICS and CICS! Basically, if the data you want is in Db2 then you don’t need CICS to manage the access to the data because that is what we pay Db2 to do. Let Db2 do the managing and data sharing.
You probably would not use DSNACICS to call a CICS program more than N times per day (where N is some number that varies – as you would expect > “it depends”). Or if performance is super-duper critical, then perhaps you would not go through the overhead of Db2 Z and then DSNACICS and then the CICS region. In those scenarios you might use a CICS client on the application server or use something like z/OS connect.
But Db2 and DSNACICS provide a simple way for distributed applications to call a CICS program. And nothing extra is required because you already have Db2. And if your application already has Db2 client software available then great. Easy. The distributed application can CALL DSNACICS
BUT. What if you have a keen developer who is building a new and modern application and they want to get the occasional data from CICS and they do not want to install Db2 client software. The CALL to DSNACICS can be easily converted to a REST service API and then it is easy for almost any modern application environment to invoke this REST service API. Easy peasey.
This requirement is something that recently happened to me! We had an interesting time making it work… and it turns out it was relatively easy. We have a CICS region with some VSAM dataset that contains some customer details like ID and name.
- The real application that manages this customer information is an old and stable CICS application. There has not been a need to “modernize” the application. The good old VSAM file is still used to manage these details for these “customers”.
For our new application, we made a new and specific CICS program whose purpose was to get this VSAM data. This new program was the world’s simplest CICS COBOL program. As I mentioned earlier, the input COMMAREA was basically defined as plain text char and numeric > PIC X(10) and PIC 9(7). No packed decimal input. Therefore, the calling program only need to pass simple plain text input!
- The COMMAREA required a REQUEST-AREA-LENGTH of COMP PIC S9(4). I think that is a CICS program requirement. But the input value did not really matter (in our case).
And then, the CICS PROGRAM mainline did a simple CICS READ to the VSAM DD and then CICS RETURN. It was all pretty simple.
For the curious, sample COBOL CODE of my program is below. 130 lines including comments. Short!
All the inputs to DSNACICS are well defined in the IBM reference documentation for Db2 (link at top)
The input parameters to DSNACICS are defined by IBM. Here is my simple understanding:
- PARM_LEVEL – always put 1 (as documentation)
- PGM_NAME – use the CICS program name
- CICS_APPLID – you should know your CICS region APPLID. It is not the CICS region started task name. But the CICS region started task JESMSGLG should tell you the APPLID! Or ask your CICS team
- CICS_LEVEL – always put 2
- CONNECT_TYPE – always put GENERIC
- NETNAME – the value does not matter to me. Put in garbage or put in 12345678
- MIRROR_TRANS – the CICS region may have a default mirror trans already. Or you can specify one here. The CICS team may need to help here
- COMMAREA has the input to match the CICS program. My case, is simple. I start it with the required but not used “CUST-REQUEST-AREA-LGTH Comp Pic S9(4).” I just put ‘xx’ as the value. And then I put the required plain text values of ID for the VSAM read! You can see my example in the DATA STUDIO screenshot below.
- COMMAREA-TOTAL-LEN – I manage to put a simple large value here. I just put 44
TEST THE CICS PROGRAM BY CALLING DSNACICS FROM A TOOL
Everyone knows that it is impossible to CALL a procedure from SPUFI or DSNTEP2. They do not accept SQL statement of CALL. Fortunately, Data Studio and other workstation tools (AQT, VSCODE, DBVisualizer) make it easy to CALL a procedure.
Below is a screen of my right click on the DSNACICS procedure name in Data Studio. I give it the proper parameters. Data Studio calls the DSNACICS procedure which calls the CICS program. This is how I confirmed the DSNACICS and COBOL program work as expected.
CALL SYSPROC.DSNACICS FROM DATA STUDIO
RESULT AFTER CALLING DSNACICS FROM DATA STUDIO
Name Type Data type Value Value (OUT)
------------------ ------ --------- ------------------- -----------------------------
PARM_LEVEL INPUT INTEGER 1
PGM_NAME INPUT CHAR GCCMEMNM
CICS_APPLID INPUT CHAR A9CGDA1C
CICS_LEVEL INPUT INTEGER 2
CONNECT_TYPE INPUT CHAR GENERIC
NETNAME INPUT CHAR 12345678
MIRROR_TRANS INPUT CHAR
COMMAREA IN/OUT VARCHAR xx0001744 1006 �0000AIYZZ,ZOZZ 2580829M
COMMAREA_TOTAL_LEN INPUT INTEGER 44
SYNC_OPTS INPUT INTEGER 2
RETURN_CODE OUTPUT INTEGER 0
MSG_AREA OUTPUT VARCHAR *NULL*
CONVERT CALL DSNACICS TO DB2 REST SERVICE API
Now that I know the CICS program and DSNACICS works as expected. I converted the CALL to a Db2 SERVICE.
Remember, a Db2 SERVICE can only consist of one SQL statement. It can be a SELECT or UPDATE or CALL.
- Obviously, if you want a series of SQL to be executed then you create a procedure first and then your REST SERVICE can call the procedure.
But in our case, we want to CALL the IBM supplied useful procedure DSNACICS.
I prefer to use JCL and BIND SERVICE to create my service. My sample JCL and BIND SERVICE are below.
- You may note that I create/BIND my service with a VERSION specified. I am a big believer in using VERSION for all my SERVICES and Db2 PROCEDURES! You should use VERSION!
- Obviously, my example below is creating a SERVICE with CICS applid hard-coded. That was my choice for my simple test. It can obviously be created as input parameter to the SERVICE!
- The only input parameter to this SERVICE is the COMMAREA!
//**********************************************************
//BINDS000 EXEC PGM=IKJEFT01
//SQLDDNAM DD *
CALL SYSPROC.DSNACICS(1,'GCCMEMNM','A9CGDA1C',2
,'GENERIC','12345678'
,'GWMN',?,499,2,?,?)
//* sample input data 'xx0001744 1006'
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
DSN SYSTEM(DDBC)
BIND SERVICE(DBCDBD1) -
NAME(REST_DSNACICS_A9CGDA1C_GCCMEMNM) -
VERSION(R2022-11-25-A) -
SQLDDNAME(SQLDDNAM) -
OWNER(DBCDBD1) -
QUALIFIER(DBCDBD1) -
DESCRIPTION('CALL DSNACICS FOR APPLID A9CGDA1C AND PGM GCCMEMNM')
//*** IF I WANT TO GET RID OF THIS SERVICE… HERE IS THE FREE SERVICE!
//*FREE SERVICE(DBCDBD1.REST_DSNACICS_A9CGDA1C_GCCMEMNM.(R2022-11-25-A))
//*-------------------------------------------------------------------*
//GRANT EXEC DBCTEP2,SSID=DDBC
//SYSIN DD *
SET CURRENT SQLID='DBCDBD1';
GRANT EXECUTE ON PACKAGE
DBCDBD1.REST_DSNACICS_A9CGDA1C_GCCMEMNM
TO PUBLIC;
INVOKE THE SERVICE AND VALIDATE FROM YOUR BROWSER
And now you have a Db2 REST SERVICE.
The great thing about SERVICEs is that the application does not need Db2 client software. It is very easy for an application developer to use a SERVICE. They do not need to know much or anything about the backend database server!
How can you, the DBA, invoke and test your service?
The easy first test is to paste the service name into your browser URL! This will do a GET on the SERVICE and your browser will return and display result of the GET which is “describes” the service. This is simple and boring. But it will prove anyone can at least see and GET the service details!
https://my.mainframe.com:6027/services/DBCDBD1/REST_DSNACICS_A9CGDA1C_GCCMEMNM
the above is the HTTPS and SECPORT. This next is for the HTTP and the open TCPPORT
http://my.mainframe.com:5027/services/DBCDBD1/REST_DSNACICS_A9CGDA1C_GCCMEMNM
INVOKE THE SERVICE AND VALIDATE FROM A TOOL THAT INVOKES A SERVICE
To be more like an application developer. You can POST your SERVICE with the required input parameters, and this will invoke it and return the result.
There are several classes of tools to invoke and validate services.
- There are browser extensions that work with REST SERVICES. I use an old CHROME extension called YARC (Yet Another REST client). It is simple for me. You can POST with input “payload” and invoke your service. (screenshot below)
- INSOMNIA and POSTMAN are apparently common windows programs for validating services. (INSOMNIA screenshot example is below)
- VS CODE has a popular extension called REST CLIENT. It should work … but I can’t figure it out.
- You can use the application developer language or environment to invoke the SERVICE (I don’t know how to do that – yet)
YARC Example
The first time you use YARC with the mainframe … it will pop up and ask for your mainframe userid/password
INSOMNIA EXAMPLE
APPENDIX: INTERESTING CAVAETS ABOUT DSNACICS
- DSNACICS is an IBM supplied stored procedure for Db2. If it has never been used before, the system DBA needs to configure it to be able to run. It is not native SQL inside. It is complicated assembler. It requires and runs inside a WLM environment! Technically, it could run in the same WLM environment and started task as the other IBM stored procedures. But IBM recommends that DSNACICS gets a dedicated environment. We call ours “ssidCICS” where “ssid” is the Db2 subsystem ID.
- as per the IBM documentation rules. DSNACICS requires security (ACF2, RACF, etc) access to rule 'ssid.REST' by the calling user. You can make the permission on this rule broad and simple for many potential callers. You still control access to each SERVICE via GRANT.
- DSNACICS has no SQL inside. Therefore, it has no package! This makes it a challenge to track how often it is called every day via your accounting trace and Db2 performance database or online monitor. The distributed application does a CALL but not much else from a Db2 perspective! I recommend that the production application userid that calls DSNACICS be a unique userid to make it easier to count and understand.
APPENDIX: Example of a CICS program that does simple read > GCCCUST
CBL TRUNC(OPT)
Identification Division.
Program-Id. GCCCUST.
*Author. Person X.
*Date-Written. 10 Oct 9999.
******************************************************************
* *
* Retrieve CUST Name *
* *
* Retrieve the CUST name for the given Plan and Certificate *
* Number. If no name is found, return spaces. *
* *
******************************************************************
/
Environment Division.
Data Division.
Working-Storage Section.
/
01 Filler Pic X(48)
Value ' *** GCCCUST - WORKING STORAGE STARTS HERE *** '.
01 WORK-CONSTANTS.
05 CALLING-PROGRAM Value 'GCCCUST' Pic X(8).
01 WORK-FIELDS.
05 CICS-RETURN-CODE Comp Pic S9(8).
05 WORK-RECORD-LGTH Comp Pic S9(4).
05 SAVE-PLAN-NUM Pic 9(7).
05 SAVE-CERT-NUM Pic X(10).
/
01 EMP-EMPLOYEE-RECORD.
Copy XC4CFEMP.
/
01 Filler Pic X(46)
Value ' *** GCCCUST - WORKING STORAGE ENDS HERE *** '.
/
Linkage Section.
01 DFHCOMMAREA.
05 CUST-REQUEST-AREA-LGTH Comp Pic S9(4).
05 CUST-REQUEST-AREA.
10 CUST-PLAN-NUM Pic 9(7).
10 CUST-CERT-NUM Pic X(10).
10 Filler Pic X(26).
05 CUST-REPLY-AREA redefines CUST-REQUEST-AREA.
10 CUST-RETURN-CODE Pic 9(4).
10 CUST-CUST-NAME Pic X(30).
10 CUST-DATE-OF-BIRTH Pic 9(7).
10 CUST-GENDER Pic X.
/
Procedure Division.
*================================================================*
* *
* Retrieve CUST Name - Mainline. *
* *
*================================================================*
Perform 0100-Initialization thru 0100-Exit.
Perform 1000-Process-Request thru 1000-Exit.
EXEC CICS
RETURN
END-EXEC.
Goback.
/
0100-Initialization.
*================================================================*
* *
* Retrieve CUST Name - Initialization. *
* *
* - Save the request parameters. *
* - Initialize the return values to their defaults. *
* *
*================================================================*
Move CUST-PLAN-NUM to SAVE-PLAN-NUM.
Move CUST-CERT-NUM to SAVE-CERT-NUM.
Move +42 to CUST-REQUEST-AREA-LGTH.
Move ZERO to CUST-RETURN-CODE,
CUST-DATE-OF-BIRTH.
Move SPACES to CUST-CUST-NAME.
Move SPACE to CUST-GENDER.
0100-Exit.
Exit.
/
1000-Process-Request.
*================================================================*
* *
* Retrieve CUST Name - Get the CUST Name. *
* *
*================================================================*
Move SAVE-PLAN-NUM to EMP-CONTRACT.
Move SAVE-CERT-NUM to EMP-CERT.
Move Length of EMP-EMPLOYEE-RECORD to WORK-RECORD-LGTH.
EXEC CICS
READ DATASET('CUSTINF')
INTO(EMP-EMPLOYEE-RECORD)
LENGTH(WORK-RECORD-LGTH)
RIDFLD(EMP-EMPLOYEE-KEY)
RESP(CICS-RETURN-CODE)
END-EXEC.
If CICS-RETURN-CODE = DFHRESP(NORMAL)
Move EMP-EE-NAME to CUST-CUST-NAME
Move EMP-EE-SEX to CUST-GENDER
Move EMP-BIRTH-DT to CUST-DATE-OF-BIRTH
Else
If CICS-RETURN-CODE = DFHRESP(NOTFND)
Move SPACES to CUST-CUST-NAME
Else
Move CICS-RETURN-CODE to CUST-RETURN-CODE
Move 'CICS ERROR' to CUST-CUST-NAME
End-If
End-If.
1000-Exit.
Exit.