The tooling CICS provides for the building and execution of SOAP Web Services providers makes it a very reasonable way to “modernize” CICS applications that are designed to be invoked via COMMAREA or Channel/Container. But, for 3270 terminal based applications–not so good out of the box. There are third-party software solutions, some of which seem pretty useful. HostBridge comes to mind. Also GT Software’s Ivory and Attachmate’s Verastream Bridge Integrator.
Another CICS application modernization paradigm, although a bit older, is the Link3270 Bridge. This facility allows you to write one program to drive one or more 3270 applications allowing the driving application to address screen fields “by name”, using the BMS Map copybook (ADS or application data structure). Since the interface is via a CICS LINK API call, the driving program could be a batch program connecting via EXCI, or ECI, another 3270 application, or . . . how about a Web Service provider program?
1 + 1 = ?
The idea here is that the Web Service tooling makes it pretty convenient to build a Web Service provider for a application that has copybooks describing the input and output. Since the interface with BMS 3270 screens is also via copybooks, it is fairly straightforward to write a Web Service provider program that front-ends a 3270 application via the Link3270 Bridge using the BMS map copybooks to feed the Web Services tooling to generate an initial WSDL What you end up with is rather like screen automation that has traditionally done using a terminal emulator’s HLLAPI, but this will perform much better (less network activity) and has the advantage that the copybooks are common so that the source management system can detect changes to the BMS map and trigger rebuilding the Web Services application.
Before starting off coding, you should check to ensure the 3270 application that you want to use for your project is going to work OK with the Link3270 Bridge. First, review the restrictions. Second, install and run the 3270 Bridge Pass-through transaction from the CA1E Supportpac which allows you to test a 3270 application via the 3270 Bridge from a terminal and gives you some good diagnostic information.
We’ll skip some steps here and use the IBM supplied sample NACT application. We already know it works with the Link3270 Bridge because, well, IBM uses it in their Link3270 sample. Plus we can use the code in that sample to check our own coding and won’t have to explain how to do bridge coding since that’s already in the sample.
Imagine a use case where a customer service user needs to find a customer given their name and from the list returned from a lookup chooses the one of whom they want so see the account details. The Web Service operations we’re going to implement to support this are,
- Account search by name
- Account display by account number
These are functions available from the NACT transaction Accounts Menu:
Click to enlarge
One bit of complexity is on the Account List interaction when there are more to list than fit on the screen and we must PF8 to scroll through the list.
Generally, this is how we plan to proceed:
- Build new copybooks, one for each web service operation we are going to build, using as a basis the NACT BMS map copybooks generated when the (DFH0MNA) map was assembled.
- Generate WSDL for these copybooks using the CICS Web service assistant (DFHLS2WS).
- Combine the two resulting WSDL so we have one that defines s single service with two operations. Edit the WSDL to adjust for specific business requirements; for example, allowing for optional fields (minoccurs=0 or nillable=true).
- Build new copybooks from this WSDL using the CICS web service assistant (DFHWS2LS).
- Code our program to implement the service.
- Test. Yeah, sure we will. 😉
This is somewhat like what the IBM Redbook Application Development for CICS Web Services refers to a meet-in-the-middle approach.
1. Build New Copybooks
For the first pass at building the copybooks, I eliminated as many of the fields I thought were not necessary and also renamed the fields from their BMS names so something more descriptive since that is what will be present in the WSDL and XML So for the AccountList operation, the request will only need Surname and Firstname (and first name will be optional–I’ll deal with that later):
*01 ACCTMNUI. 01 AccountListRequest. * 02 SNAMEMI PIC X(18). 02 Surname PIC X(18). * 02 FNAMEMI PIC X(12). 02 FirstName PIC X(12).
And the reply:
*01 ACCTMNUO REDEFINES ACCTMNUI. 01 AccountListReply. * 02 DFHMS1 OCCURS 6 TIMES. * 03 SUMLNMO PIC X(79). 02 SummaryLine PIC X(79) OCCURS 6 TIMES. * 02 MSGINVMO PIC X(65). 02 Message PIC X(65).
The SummaryLine is actually multiple columns on the screen which could be broken up into separate fields (and thus separate WSDL/XML elements).
Similar process for AccountDisplay.
2. Generate WSDL
This is the sort of JCL I used to generate WSDL from these copybooks:
// JCLLIB ORDER=(XXXXXXXX.XDFHINST) //DFHLS2WS EXEC DFHLS2WS, // JAVADIR='java/J6.0', // PATHPREF=, // REGION.JAVAPRG1=256M //INPUT.SYSUT1 DD * PDSLIB=//XXXXXXX.SRC.COB REQMEM=ALSTREQ RESPMEM=ALSTREP LANG=COBOL PGMNAME=LISTWS TRANSACTION=NAWS URI=Account PGMINT=COMMAREA WSBIND=/tmp/AccountList.wsbind WSDL=/tmp/AccountList.wsdl LOGFILE=/tmp/AccountList.log MAPPING-LEVEL=2.2 SOAPVER=ALL
3. Combine the WSDL
This is a bit complicated but the indentation helps. Also, I used a different program name for each DFHLS2WS run so it would be easier to keep things straight. There programs are phony anyway since we will never use the WSBIND files from these two assistant runs. First I copied the AccountList.wsdl to AccountService.wsdl then used ISPF PDF Edit CUT and PASTE to copy sections of AccountDetails.wsdl into it.
- The schemas between <types> & </types>
- The messages
- The operation under portType
- The operations in the binding sections.
- Change all the “targetNamespace” values to be the same.
CHANGE ALL "DETAILWS.ADET" "LISTWS.ALST", for example.
- Also removed an extraneous field that is a literal on the map for Charge Limit.
- I left a bunch of names as LISTWSxxxxx even when the WSDL now includes the detail operation as well, but I think that is pretty irrelevant to the final outcome. It you are doing this for real, you should probably use a real WSDL editor and rationalize the names for better documentation.
In the AccountListRequest schema, I edited the FirstName element to have nillable=”true” since the element is optional. In the AccountListReply schema, I changed minOccurs for SummaryLine from
The result: AccountService.wsdl
4. Build new Copybooks
Now we feed the WSDL though the CICS Web service assistant DFHWS2LS to generate a WSBIND CICS can use and new copybooks that reflect the changes we’ve made.
- A WSDL with multiple bindings (SOAP and SOAP12, for example) and you have to specify which one to the utility with the BINDING= parameter.
- A WSDL with multiple operations requires PGMINT=CHANNEL instead of COMMAREA.
- INLINE-MAX-OCCURS=6 so that all of the SummaryLines will fit without an extra container.
// JCLLIB ORDER=(DFH320.XDFHINST) //DFHWS2LS EXEC DFHWS2LS, // JAVADIR='java/J6.0', // PATHPREF=, // REGION.JAVAPRG1=256M //INPUT.SYSUT1 DD * PDSLIB=//USER.SRC.COB REQMEM=NACTRQ RESPMEM=NACTRP LANG=COBOL INLINE-MAXOCCURS-LIMIT=6 PGMNAME=NACTWS TRANSACTION=NAWS URI=Account PGMINT=CHANNEL WSBIND=/tmp/AccountService.wsbind WSDL=/tmp/AccountService.wsdl BINDING=LISTWSHTTPSoapBinding LOGFILE=/tmp/AccountService.log MAPPING-LEVEL=2.2
5. Time to Code.
We’ll start out coding of NACTWS with a copy of SDFHSAMP(DFH0CBRL) which already has the Link3270 Bridge logic in it and we’ll add the Web Services support to it. DFH0CBRL takes it’s input from a COMMAREA, copybook SDFHSAMP(DFH0CBRA); the new program will use containers mapped by the copybooks we created above. Hmm, all the of the fields names are different.
- Include the request copybooks int he Linkage section:
Linkage Section. 01 srch-request. copy NACTRQ01. 01 list-request. copy NACTRQ02.
and the reply copybooks in working-storage:
01 srch-reply. copy NACTRP01. 01 list-reply. copy NACTRP02.
- Determine the type of request from the Operation name:
77 ws-operation pic x(32) value spaces. 88 srch-req value 'LISTWSOperation'. 88 disp-req value 'DETAILWSOperation'. and EXEC CICS GET CONTAINER('DFHWS-OPERATION') INTO(ws-operation) END-EXEC if srch-req perform search-request else perform display-request end-if.
- Get the request parameters from the predefined container, for example for the AccountList request:
EXEC CICS GET CONTAINER('DFHWS-DATA') SET(ADDRESS OF srch-request) FLENGTH(container-len) END-EXEC move Surname of srch-request to snamemi move length of Surname of srch-request to snameml move Firstname of srch-request to fnamemi. move length of Firstname of srch-request to fnameml.
The result: NACTWS.COB
Here are some test results via SoupUI.
I didn’t get around to putting the in PF8 support, but otherwise the web service seems functional.. Perhaps in the future I’ll make this into a RESTful service using the CICS provided Atom service.