DSNACICS. Why use DSNACICS? calling DSNACICS through REST API – A user experience

Posted By: Brian Laube Technical Content,
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. 

  1. 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)
  2. INSOMNIA and POSTMAN are apparently common windows programs for validating services. (INSOMNIA screenshot example is below)
  3. VS CODE has a popular extension called REST CLIENT. It should work … but I can’t figure it out. 
  4. 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.