Prerequisite reading: JazzUGSOA1.htm
On the Jazz web site SOATest1 is a program that invokes a web service: -
There is a
service, written in VB.NET, that is invoked by the web page. For our first SOA program we’ll write the
equivalent as a Jazz program running in z/OS CICS that will return the time in
As this is our very first web service, we must first set up the appropriate configuration details. You may need the assistance of your system programmer for this.
Open the Jazz workbench and click the [Configure] button. Click the z/OS tab: -
The details that you’ll need to configure are in the Web Services section at the bottom right.
HFS. This means “Heirachical File System”. As you create web services various objects will be put into the z/OS Unix File System, so you need to define where these will go. You can probably leave this with its default value, /u/@lcgroup/@mode. With the value given above in the Group field in the ISPF section this will become /u/manajazz/Provider for provider programs, and /u/manajazz/Requester for programs using INVOKE to invoke other web services. Although in this chapter we’re concerned with a provider program, we’ll set up the CICS system for both providers and requesters.
The HFS needs to name folders where you have update rights. These folders must exist, and must contain subfolders /shelf and /pickup. Thus with the parameter values above we need to have created the following files in our zOS Unix file system: -
Click [Check HFS] to check that these folders exist. If they do not, then they will be created (subject to a prompt).
A note about file names: Jazz has imposed these rules: -
· The HFS is named /u/@lcgroup/@mode, where @lcgroup is the lower-case CICS group name for this project and @mode is either “Provider” or “Requester”. Thus in my case the HFS is named /u/manajazz with subfolders /Provider and /Requester
· These folders contain subfolders /shelf and /pickup.
· For each program there will be two or three objects in the HFS, a .wsbind file, and either a .wsdl file or two .json files. The system (not Jazz) requires these extensions to be in lower case, i.e. not .WSDL nor .WSBIND
· Web service provider or requester programs can’t be named “shelf” or “pickup”
The first two rules are not required by zOS or CICS, but there seemed no reason not to follow this simple convention. If you decide not to follow this convention then you’ll create extra work for yourself: for example you’ll have to manually copy the .wsdl and .wsbind files.
Ports. You need to provide the port numbers for HTTP and HTTPS access. Get your system programmer to tell you what values you should give: normally any number above 1024 that is not already used will do. 80 and 443 are zOS defaults, but your system programmers may have restricted access to these. The examples use ports 9014 and 9015 for testing, but there’s nothing special about these numbers.
Provider. When you process a web service provider program then after the program has been compiled and linked a DFHLS2WS or DFHLS2JS step is run. DFHLS2WS and DFHLS2JS are two of the Web Services Assistant programs provided by IBM. LS2WS means “Language Services to Web Services” and its function is to create WSDL and binding files from the program information: this is used when your PROGRAM statement includes option WSDL. LS2JS is the equivalent that is used when your PROGRAM statement contains the JSON option: it creates a pair of JSON message descriptions for the input and output messages. You can click the label “Provider” and a notepad window will open allowing you to see and edit this step: it probably looks like this: -
//*** CREATE WSBIND AND WSDL from program information
// SET QT=''''
//DFHLS2WS EXEC DFHLS2WS,REGION=0M,
//INPUT.SYSUT1 DD *
//COPYWS1 EXEC PGM=BPXBATCH,REGION=0M,PARM='SH cp @email@example.com @firstname.lastname@example.org'
//STDOUT DD PATHemail@example.com',PATHOPTS=(OWRONLY,OCREAT),
//STDERR DD PATHfirstname.lastname@example.org',PATHOPTS=(OWRONLY,OCREAT),
//COPYWS2 EXEC PGM=BPXBATCH,REGION=0M,PARM='SH cp @email@example.com @firstname.lastname@example.org'
//STDOUT DD PATHemail@example.com',PATHOPTS=(OWRONLY,OCREAT),
//STDERR DD PATHfirstname.lastname@example.org',PATHOPTS=(OWRONLY,OCREAT),
//* Still needed - CICS commands: newcopy, Pipeline scan
The Jazz parameters like @hfs will be replaced from your configuration settings and program information. We’ll return to this later.
Pipeline. You need to give the name of the provider pipeline. If this doesn’t exist yet you’ll be creating it below: come back to configuration and add it then. It will be needed when you create a web services provider program as it is used in the value of @URIProv.
A Web Service Provider program is a CICS program and like classical CICS programs it will use the JZL procedure JZCompileCICS.JZL, but unlike a classical CICS program the compile is followed by a DFHLS2WS or DFHLS2JS job step. The DFHLS2WS/DFHLS2JS step executes a procedure: -
//DFHLS2WS EXEC DFHLS2WS,REGION=0M,
rather than directly executing a program with EXEC PGM=xxx. You may need something like this so that the procedure reference DFHLS2WS is properly resolved: -
//JOBPROC JCLLIB ORDER=DFH510.SVSC.CUSTOM.INSTALL
If this is needed then put it into the Proclib textbox of the Configuration page (z/OS tab).
We need to create at least one TCPIPSERVICE. We may create two, one for HTTP (clear-text transmission) and one for HTTPS (encrypted-text transmission).
To create the TCPIPService, start a CICS session and use transaction CEDA to define the TCPIPSERVICE: -
CEDA DEF TC(MANAJAZZ) GRO(MANAJAZZ) URM(NONE) PORT(9014) PRO(HTTP) TR(CWXN)
1. In this context we cannot use Jazz parameters like @lcproject, so we have to spell out “MANAJAZZ”
2. DEF, TC, etc are abbreviations: you only need to give enough of a CICS operand to make it unique.
3. Here operand TC calls the TCPIPSERVICE MANAJAZZ, which is the same name as the group (operand GRoup).
4. In my configuration I’d defined 9014 as the port for HTTP, and 9015 for HTTPS. These numbers are entirely arbitrary, provided that they are > 1024 and < 32767.
5. The transaction CWXN is required for both HTTP and HTTPS.
6. URM(NONE) Note that coding "NONE" does not tell CICS that there is no URM. Rather, it tells CICS to look for a program named "NONE" if there is no match of path on the incoming request to the installed URIMAP resouces. "NONE" is used as an aid to diagnostics -- if you see a CICS message saying that Program "NONE" was not found, you know right away that there's a problem with the path and URIMAP matching.
To create a second TCPIPService for HTTPS: -
CEDA DEF TC(MANAJAZS) GRO(MANAJAZZ) URM(NONE) PORT(9015) PRO(HTTP) TR(CWXN)
7. The service name has to be different: we can’t have two TCPIPSERVICEs both called “MANAJAZZ”
8. Note that PROtocol is still HTTP. It is not set to HTTPS.
9. The transaction too is the same, staying as CWXN
10. The PORT is the number that we defined in configuration for HTTPS
This hasn’t been tested: I haven’t yet used a HTTPS link
Finally we need to define a pipeline for the Provider. Again, using CEDA. Shown here as a screen snapshot because of the length of the configfile value: -
Enter the name of this pipeline, MNJZPROV in this example, into the Jazz configuration.
While we’re at it, we’ll create a second pipeline for requester programs. That’s the subject of a later chapter and not needed just yet, but it’s convenient to create them together.
1. I have named the pipelines MNJZPROV and MNJZREQR. The names should be unique and 8 characters or less. I would have named them “MANAJAZZ-Provider” and “MANAJAZZ-Requester” but these names were too long and weren’t allowed by CEDA.
2. Description can be any text
3. Status, Respwait: left as default values
4. Configfile: this is read-only. I’ve directly used samples provided by IBM.
5. Shelf and Wsdir are named following the naming conventions discussed above.
Once these pipelines have been defined, they need to be installed, perhaps by installing the whole group
CEDA INSTALL GROUP(MANAJAZZ)
or by specifically installing these components.
CEDA INSTALL PIPELINE(MNJZPROV) GROUP(MANAJAZZ)
CEDA INSTALL PIPELINE(MNJZREQR) GROUP(MANAJAZZ)
Configuration is now complete. You won’t need to do this again.
Creating a Jazz web service is similar to creating any other program. We start with the New dialog, selecting Logic/New Web Service and giving a name for our program: -
Type allows us to chose either WSDL or JSON communication, and will cause either WSDL or JSON to be added to the Jazz PROGRAM statement leading to either DFHLS2WS or DFHLS2JS being used to create the message formats. Which to choose? This is a good place to start: Understanding SOAP and REST Basics And Differences
WSDL web service programs can communicate through the COMMAREA, which Jazz would name by adding “C” to the program name as it does with classical CICS programs. More usually however we’ll use a named container. Jazz provides a default name by putting JZC in front of the program name. We could change these names. Web service programs communicate with EITHER Commarea or Container, and you won’t use both: this is not like a Classical CICS program where you have both a screen and a Commarea. IBM have provided the Commarea options for compatibility with old programs, making it easier to convert old COBOL CICS service programs into versions that will provide their data as web services instead of through EXEC CICS INVOKE. We should use the Container option.
For JSON messages we cannot use COMMAREA.
We click [Finish] and the next thing we see is a Jazz workbench with an initial container definition for us to edit. Jazz creates container definitions with three records, a control record that gives the names of the input and output messages, and records for each of the messages: -
We edit the input and output fields in this record.
If there is a COMMAREA name then this is defined in the same way as a container.
Fields placed within an OUTPUT group cannot receive data on input as Jazz initialises them at the start of the program
Once the container and/or commarea has been defined we click [Exit]. Jazz saves the container (or Commarea) definition and displays the program, such as it is at this stage: -
The program structure now exists to read the input message, and send it back. Of course we need to write some logic in between to calculate the result that we want. Essentially our logic is: -
Result = 'Hello ' && name && '. The time in
so we write this, get rid of the unwanted comments, and click [Check]. Here is our complete program: -
The program has now put the result that we want into the output message, for example
“Hello Robert. The time in
by concatenating (operator &&) various string constants with the Name from the input message and the system’s date and time ($Now built-in function). It only remains to send this output message back to the service requestor, which REPLY does. REPLY needs no arguments since we’ve already set up the output message.
Click [Process] and, as with any other Jazz program, the Jazz program is converted to COBOL and a job submitted to compile and link it. There are some extra steps in this job: after the compile and link (and subject to condition codes)
1. A web services assistant step is executed to create the relevant .wsdl and .wsbind entries into the HFS folder.
2. These files are copied into the pickup directory
Our web service program is almost ready to be used. All we have to do is enter a couple of CICS commands: -
need to define our program into our CICS group.
We can do this with the CICS command
CEDA DEFINE PROGRAM(GETTIME) GROUP(MANAJAZZ)
If we’re replacing the program then it will already be defined into this group. We’ll need to tell CICS to use the new copy: we do this with
CEMT SET PROGRAM(GETTIME) NEWCOPY
4. We need to do a pipeline scan: -
CEMT PERFORM PIPELINE(MNJZPROV) SCAN
The program is ready for testing. We’ll invoke it with our favourite web services development software: Eclipse, Rational, Visual Studio, etc. I’ll illustrate the process using a free test tool, SOAPUI, that you can download here. I created a SOAPUI project: -
Click [OK] and the web service is discovered, and a project created. Note that the WSDL is case-sensitive: if your program name was “Gettime” or “GETTIME” then this initial WSDL won’t discover the web service and a valid project won’t be created. Once a valid project has been created in SOAPUI, locate the request node, double click this, and the test form opens. Fill in the input data (left hand panel), in this case giving the length and value for Name, and setting the length of Result and Error to 0. Then click and the message is sent to the service, and the results displayed in the right-hand panel: -
You may choose
to write a test requestor with your favourite client programming language. For example, in the video http://www.jazzsoftware.co.nz/Videos/demo3SOA/demo3SOA.html
the web service GetTime is tested from a web page. I wrote the logic for this page with Visual Studio, using VB for ASP.NET. In my Visual Studio project I created a web service reference using the URL http://22.214.171.124:9014/MNJZPROV/gettime?wsdl I called this service “GetTime” within my VB project. I then wrote a web page (called zOSTest). For this page I used this logic to get the data from the mainframe GetTime service: -
Public Class zOSTest1
Protected Sub btnRespond_Click(sender As Object, e As EventArgs) Handles btnRespond.Click
Dim zOStest As New GetTime.GETTIMEPortClient
Dim PgmInterface As New GetTime.ProgramInterface
Dim Name As New gettime.ProgramInterfaceIgettimeName
Name.jzd_Name = txtName.Text
Name.jzl_Name = Len(txtName.Text)
Dim IGettime As New gettime.ProgramInterfaceIgettime
IGettime.Name = Name
PgmInterface.Igettime = IGettime
Dim Result As gettime.ProgramInterface1 = zOStest.gettime(PgmInterface)
lblResponse.Text = Result.Ogettime.Result.jzd_Result
This is not a complicated as it looks. The SOATest1 logic is
Dim SOATest As New SOATest.Service1Client
lblResponse.Text = SOATest.SOATest1(txtName.Text)
so I initially wrote
Dim zOStest As New gettime.GETTIMEPortClient
lblResponse.Text = zOStest.gettime(txtName.Text)
However zOStest is not the same kind of object as SOATest, and its argument formats aren’t compatible with the text fields of the web page. The incompatibility was resolved by defining arguments of the correct types like Dim PgmInterface As New GetTime.ProgramInterface, and working outward until properties were found that could be assigned from/to the text fields.
Hopefully you’ll be able to diagnose problems with your web services with test tools like SOAPUI or your own test routines and working at the high level of Jazz. You shouldn’t need to descend to the level of COBOL, but if the problems are obscure, or you suspect that Jazz is generating incorrect code, there may be no alternative. If you do find an error that needs this approach and it’s a fault in Jazz, please let us know. You will probably need the help of a system programmer: the fault may be in your zOS set up. While Jazz Software can help you if Jazz is generating the wrong COBOL or JCL, we do not have system programming expertise.
With a classical CICS program (3270 type) you might use the CICS Execution Diagnostic Facility with transaction CEDF. With a web service you use this with command CEDX and transaction CPIH. Issue the CICS command
from a CICS terminal (a 3270 emulator running CICS). Then invoke your web service as you would normally, for example by clicking the Request button in your SOAPUI test window. You will see your CICS terminal respond with a CEDF display showing the before and after states for every EXEC CICS statement in the COBOL program. The first CICS statement in all Jazz-generated web services will be like this, although with different names.
GET CONTAINER(JZContainerName) INTO(IWSPG1R) RESP(JZ-RESPONSE)
CEDF/CEDX only gives diagnostics at the points where COBOL uses EXEC CICS. If you need to diagnose code between these points and you don’t have a test facility that allows you to step through all your CICS COBOL statements interactively, not just the EXEC CICS statements, then you may find routine BR14 useful. (It was developed for our own use but is provided with Jazz). BR14 is a “do nothing” routine. Modify the COBOL by inserting statements like: -
EXEC CICS LINK PROGRAM(‘BR14’) COMMAREA(Field) END-EXEC
where you want CEDX to display diagnostics. The value of Field will be available in the displays invoking BR14. BR14 does not change your program logic, or the value of the parameter Field, in any way.
If you don’t get anything useful from CEDX, in particular you don’t see “About to execute command GET CONTAINER …”, followed by other displays as various EXEC CICS commands are executed, then there is something wrong in your zOS system. If this is your first attempt to develop a web service then consult your system programmer. Most likely there is something wrong in the set up that delivers messages between your client program and the web service.
If you have previously had successful web service tests in this environment, then perhaps the CICS Load Library is full. In early 2017 I spend a very frustrating few days solving this problem: -
1. I had developed some web services tests like those demonstrated in the videos on our web page. I had developed a service WSPG2A that was working perfectly.
2. I tried to develop the next web service, WSPG3A. The job seemed normal, and I was able to discover the WDSL and develop a SOAPUI test. However when I ran this test there was a SOAP message “Target program WSPG3A failed with abend code AEI0”.
3. Abend AEI0 means that a program couldn’t be found, but I could see program WSPG3A in the zOS load library and in the CEDA display of the MANAJAZZ CICS group. However the CICS command CEMT SET PROGRAM(WSPG3A) NEWCOPY returned error “Program not found”. Nothing in the job that compiled program WSPG3A and ran DFHLS2WS to create WSDL and binding objects indicated an error. CICS command CEDA DEFINE PROGRAM(WSPG3A) GROUP(MANAJAZZ) had returned a normal result.
4. A web search for Abend AEI0 suggested a faulty EXEC CICS LINK … or EXEC CICS XCTL with a short program name, but this was not the cause here. Another web page suggested that I might find the error in the CICS logs, but it implied that this was difficult and time consuming, and besides I didn’t know where to find the CICS logs.
5. By this time I was trying to create a program WSPG3A that was identical to program WSPG2A except for the program name. Substitution of “3” for “2” in the program name and no other change should not cause a problem, so I guessed that there was a problem with the load library. I found that it was 96% full. I cleared space by deleting old programs that I didn’t want any more, the library utilization dropped to 54%, and the problem was solved. I ran the normal Jazz [Process] that created COBOL and JCL and submitted a job to compile it and run DFHLS2WS. Now CEMT SET PROGRAM(WSPG3A) NEWCOPY returned a normal response, and my SOAPUI test worked as expected.
Here we’ve written an extremely basic web service provider. This service doesn’t access any file data, and its entire logic was dealt with in one line. In later chapters we’ll start to get real, dealing with some of the problems that we’ll encounter in the real world: -
Accessing files. We’ll write a program to read and return a VSAM record
Reading and updating record sets. We’ll write programs to read and update a parent/child records set: customers and orders.