Providing Web Services with ZOS

Providing Web Services. 1

Configuring our System to Provide our First Web Service. 1

Step 1   Configure the Jazz Workbench for Web Services - ZOS.. 1

Step 2.  Check the JCL for Compiling CICS Programs. 1

Step 3.  Create One or Two TCPIPService[s] 1

Step 4.  Define a pipeline. 1

Writing a Jazz Web Service. 1

Defining COMMAREA Records. 1

Defining Program Logic. 1

Testing a Web Service. 1

COBOL-Level Testing of Web Services. 1

Review: The Next Steps. 1

 

Prerequisite reading: JazzUGSOA1.htm

 

This chapter is written for ZOS users.  Micro Focus users should read the similar chapter JazzUGMFStep4.htm

Configuring our System to Provide our First Web Service

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.  

Step 1   Configure the Jazz Workbench for Web Services

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.

Step 2.  Check the JCL for Compiling CICS Programs

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).

Step 3.  Create One or Two TCPIPService[s]

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.  

Step 4.  Define a pipeline

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.

Writing a Jazz Web Service

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.

 

Defining Program Logic

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.    

Testing a Web Service

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.

COBOL-Level Testing of Web Services

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.

Using CEDF

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.

What if you don’t get any CEDX diagnostics?

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.

Review: The Next Steps

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

·         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.