Configuring
our System to Provide our First Web Service
Step
1 Configure the Jazz Workbench for Web
Services - ZOS
Step
2. Check the JCL for Compiling CICS
Programs
Step
3. Create One or Two TCPIPService[s]
COBOL-Level Testing of Web Services
Prerequisite reading: JazzUGSOA1.htm
This chapter is written for ZOS users. Micro Focus users should read the similar chapter JazzUGMFStep4.htm
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: -
u/
manajazz/
Provider/
shelf/
pickup/
Requester/
shelf/
pickup/
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,
// TMPFILE=&QT.&SYSUID.&QT
//INPUT.SYSUT1
DD *
LOGFILE=@HFS/@Program.log
PDSLIB=//@Copy
REQMEM=@Reqmem
RESPMEM=@Respmem
OPERATION-NAME=@Program
LANG=COBOL
MAPPING-LEVEL=3.0
PGMNAME=@Program
@Pgmint
@Contid
WSDL=@hfs/@Program.wsdl
WSBIND=@hfs/@Program.wsbind
URI=@URIProv
/*
//COPYWS1
EXEC PGM=BPXBATCH,REGION=0M,PARM='SH cp @hfs/@program.wsdl
@hfs/wspickup/@program.wsdl'
//STDOUT
DD PATH='/tmp/@userid.stdout',PATHOPTS=(OWRONLY,OCREAT),
//
PATHMODE=SIRWXU
//STDERR DD
PATH='/tmp/@userid.stderr',PATHOPTS=(OWRONLY,OCREAT),
// PATHMODE=SIRWXU
//COPYWS2
EXEC PGM=BPXBATCH,REGION=0M,PARM='SH cp @hfs/@program.wsbind
@hfs/wspickup/@program.wsbind'
//STDOUT
DD PATH='/tmp/@userid.stdout',PATHOPTS=(OWRONLY,OCREAT),
//
PATHMODE=SIRWXU
//STDERR DD
PATH='/tmp/@userid.stderr',PATHOPTS=(OWRONLY,OCREAT),
// PATHMODE=SIRWXU
//* 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)
Notes:-
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)
Notes: -
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.
Notes: -
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.
6.
The
examples above are setting up SOAP (=WSDL) pipelines. You will use a different config file for a
REST (=JSON) pipeline. If you want to
support both SOAP and REST you’ll need to set up four pipelines, a pair for
each format.
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
Refer to JazzWKWebservice.htm for more detail about the controls on this form.
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. The name of the container definition is not DFHWS-DATA, but is a combination of the service and program names: -
We may edit the input and output records now, or later by right-clicking the WEBSERVICE keyword in the PROGRAM statement.
Once the container has been defined we click [Exit]. Jazz saves the container definition and displays the program: -
The program structure now exists to read the input message,
and send it back, and the logic required by the function we requested. In this example we requested that the
Employee record from the Sample DB2 database be retrieved by EMPLOYEE.EMPNO or EMPLOYEE.EMPNO and displayed.
The program above contains all the logic necessary for this. The generator will create programs to display
or update single records, or display or update parent/child record sets, with
all or selected fields from each record, but even with this power the generator
is just a start. We may need to write
more Jazz statements to read further records, or to do calculations. As we make changes to the programs logic, we
can edit the message formats by right-clicking
WEBSERVICE.
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 (or .json) 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: -
3.
We 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 need a way to invoke it, such as with a general test tool like SOAPUI (now called ReadyAPI) or Postman, or perhaps our favourite client-side development software: Eclipse, Rational, Visual Studio, etc. I’ll illustrate the process here using the GetTime program which was the first example in the Providing Web Services video using SOAPUI. 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 (see Note 1)
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.
In 2015, when input fields could be defined with format VARCHAR, it worked perfectly: -
Now however it returns results like this: -
“Hello Robert . The time in Dallas is 29 Sep 2019, 15:52:27”
This problem would be fixed if NAME were defined with VARCHAR, but MANASYS has imposed imposed a rule that all input data must be CHAR because otherwise invalid data cannot be handled properly by ACCEPT, but instead causes the transaction to fail with a CICSFault before it reaches your program. There are several easy ways of ensuring that unwanted blanks are removed: here we add TRIM.
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://192.86.32.59: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
Inherits
System.Web.UI.Page
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
End Sub
End Class
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
Postman 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 zOS 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
CEDX CPIH,ON
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 JZBR14 useful. (It was developed for our own use but is
provided with Jazz). JZBR14 is a “do
nothing” routine. Modify the COBOL by inserting statements like: -
EXEC CICS LINK PROGRAM(‘JZBR14 ’) COMMAREA(Field) END-EXEC
where you
want CEDX to display diagnostics. The
value of Field will be available in the displays invoking JZBR14. JZBR14 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.
·
Accessing files. We’ll write a program to read and return a
VSAM record
·
Updating files. We’ll write a program to update a VSAM
customer file through a web service.
·
Reading and updating record sets. We’ll write programs to read and update a
parent/child records set: customers and orders.
But before we go on with this, the next chapter deals with the reverse problem:
writing a program to invoke an existing web service. Or click here to
skip this chapter and go on with the following one, where you’ll learn how to
access file data.