Web Service Discovery

Contents

Web Service Discovery. 1

Introduction. 1

Discovering a Web Service Reference from INVOKE ? when a COPY exists. 1

Discovering New Services – Part 1, Discovering Operations. 1

Discovering WSDL services. 1

Discovering JSON services. 1

Discovering New Services – Part 2, Discovering Message Formats. 1

Appendices. 1

Jazz Web Service Definitions. 1

Add Service Reference Information. 1

Parking. 1

Creating a Web Service Description. 1

Exchanging Data with SOA Objects. 1

Selecting an operation. 1

Continuing our Program.. 1

Handling the Reply. 1

Dealing with WSDL Conversion Errors. 1

More Parking. 1

 

Introduction

A web service is invoked with a statement like

INVOKE MyJSv-JSPG1(IJSPG1.*) REPLY(OJSPG1.*);

Like a CALL statement, an INVOKE statement requires a preceding COPY (containing DEFINE) statement defining the input and output message formats, so this statement will be preceded by

COPY MyJSv-JSPG1;

The name of this service, MyJSv-JSPG1, suggests that this is a program JSPG1 that we have developed ourselves, and so we’ll have this copy book.  However most web services that we invoke will have been developed by others, probably people we don’t know and with languages other than MANASYS Jazz.  Unless we wrote the service, we need to discover the message formats and create the Jazz COPY book. Many web services provide descriptive information so that requesting programs can discover these formats.  SOAP (WSDL) web services, and REST(JSON) services that follow the Swagger (Open UI) standards, have message formats that can probably be discovered from information available at their URL.  MANASYS Jazz has features built in that can discover this information and create the COPY book containing the Jazz-format message description. 

 

We start by writing

            INVOKE ?;

in our program and clicking [Check].

Discovering a Web Service Reference from INVOKE ? when a COPY exists

When Jazz reaches the INVOKE ?; statement the “Add Service Reference” dialog results, displaying the form below. The combo box, and list of operations at that service, will be blank if this is the first time that you’ve tried to discover a web service, and if you haven’t created any web service provider programs of your own. Otherwise the Combo box is populated with the services that you already know about, including the services that you have created yourself.  Here I’ve selected the second entry, which are the JSON services that I’ve created.

 

At this URL there are several operations: each operation is a separate program.   MyJSv is one of our own services (the service reference name MyJSv is a giveaway), so the required COPY book describing the service will already exist in our Jazz Copybooks folder.  We click JSPG1 and INVOKE ?; is replaced with

COPY MyJSv-JSPG1;

INVOKE MyJSv-JSPG1(IJSPG1.*) REPLY(OJSPG1.*);

 

We can now write logic before the INVOKE statement to set values in the input record, IJSPG1, and after it to handle the results returned in OJSPG1.

 

But how do we discover new web services that we haven’t developed ourselves?  Discovering New Services tells you about this.  However if this is your first contact with web services you might like to read Jazz Web Service Definitions first to get an understanding of the structure of a COPY book describing a web service.

Discovering New Services – Part 1, Discovering Operations

What if the service is not one that we developed ourselves?  We will need a description of the service so that we can create the COPY book describing it and so know what fields required in the input message and what we’ll get back in the output message.  But if the service was developed by somebody else that we’ve never met, using technology different to ours, then how do we get this description?  Fortunately, many web services provide a description of their interfaces in a standard form, so with any luck all we need to know is the service’s description URL, and its type, JSON or WSDL.

 

For example, here is a public SOAP API that we created for some testing: -

            http://www.jazzsoftware.co.nz/SOATesting/Service1.svc. 

Its description can be found at http://www.jazzsoftware.co.nz/SOATesting/Service1.svc@WSDL

 

And here is a public sample REST API

Petstore 2.0: http://petstore.swagger.io/v2/

Its description can be found at https://petstore.swagger.io/v2/swagger.json

           

We start with a Jazz program that includes INVOKE ?; and click [Check].  On reaching this statement the Add Service Reference dialog is displayed, but instead of selecting an existing service we copy/paste or type a new URL into the combo, give a service reference name, and type.

 

Service reference names cannot be longer than 5 characters. This restriction results because Jazz may use an IBM CICS utility to create record layouts which requires the service name to be 6 or fewer characters, after prefixing the name with “I” or “O”.   The TYPE must be either JSON or WSDL.

Discovering WSDL services

WSDL (SOAP) services will usually respond with WSDL when the service URL is followed by ?WSDL, so to discover the operations at http://www.jazzsoftware.co.nz/SOATesting/Service1.svc we give this URL, and click [Get Svc].  Jazz adds the ?WSDL for us, and responds: -

 

Discovering JSON services

For JSON (REST) services there is no similar standard relating the service URL to the description URL, so we may need to enter the description URL directly.  If we give a URL that does not end with .json, Jazz will add this extension by default.  Here we’ve entered the description URL for the petstore: -

Discovering New Services – Part 2, Discovering Message Formats

As with MyJSv, we will click on one of the operations for INVOKE ? to be replaced with something like 

COPY MyJSv-JSPG1;

INVOKE MyJSv-JSPG1(IJSPG1.*) REPLY(OJSPG1.*);

But at the moment all we have is a list of operations (programs), and we don’t have any information about the message formats, so when we click one of the operations, Jazz can’t find the appropriate copy book.  It reacts by displaying the GetWebServiceDescription dialog.  Here we’ve clicked User of service PtStr: -

 

 

The left button, [Get json from Service], attempts to download json data describing the  message formats from the service URL.  [Browse for json] initiates a Windows Explorer dialog to locate a suitable file that already exists locally.  If a file is located by either button the [Create Jazz] button is enabled.  Click this and the web service description is converted from .json to a Jazz format definition: in this case named PtStr-user.jzc.

 

The same form appears with a wsdl service.  Here we’ve clicked operation SOATest1 of the WSDL service JZTs2: -

 

Apart from working with .wsdl instead of .json the function is as described above.

Appendices

Jazz Web Service Definitions

MySvce-JSPG1 is a Jazz service definition created by Jazz when program JSPG1 was generated, and it illustrates the main features of Jazz service definitions.  Definitions derived from external WSDL or JSON web services will not have COPY statements, nor use LIKE definitions and ASSIGN properties initially, but it is often worthwhile to edit the definition created for you to use these and other Jazz language features, as this will allow you to reduce the amount of procedural code that you have to write.

*# Last Updated by JAZZUSR at 13/02/2020 2:26:00 PM

*# You may edit this definition: right-click the 'WEBSERVICE' keyword of the PROGRAM statement.

COPY Employee;

COPY TYPES;

DEFINE MyJSv-JSPG1 SYSTEM DATA([Not in COBOL

    INPUT VARCHAR(6) VALUE 'IJSPG1',

    OUTPUT VARCHAR(6) VALUE 'OJSPG1',

    MType CHAR(4) VALUE 'JSON',

    URL VARCHAR(35) VALUE 'http://localhost:9003/cics/services');

DEFINE IJSPG1 SERVICE INPUT DATA(

    JZ-Employee-Skip SMALLINT VALUE 0,

    JZ-Employee GROUP,

        EMPNO CHAR(6) ASSIGN EMPLOYEE.EMPNO, [KEY

        WORKDEPT CHAR(3) ASSIGN EMPLOYEE.WORKDEPT, [DKEY

        END GROUP);

DEFINE OJSPG1 SERVICE OUTPUT DATA(

    ERROR VARCHAR(80),

    JZ-Employee-ReadTo SMALLINT VALUE 0,

    JZ-Employee-NbrReturned SMALLINT VALUE 0,

    JZ-Employee-ReturnCode LIKE Types.ReturnCode,

    JZ-Employee (1) GROUP,

        EMPNO LIKE EMPLOYEE.EMPNO ASSIGN EMPLOYEE.EMPNO,

        FIRSTNME LIKE EMPLOYEE.FIRSTNME ASSIGN EMPLOYEE.FIRSTNME,

        MIDINIT LIKE EMPLOYEE.MIDINIT ASSIGN EMPLOYEE.MIDINIT,

        LASTNAME LIKE EMPLOYEE.LASTNAME ASSIGN EMPLOYEE.LASTNAME,

        WORKDEPT LIKE EMPLOYEE.WORKDEPT ASSIGN EMPLOYEE.WORKDEPT,

        PHONENO LIKE EMPLOYEE.PHONENO ASSIGN EMPLOYEE.PHONENO,

        HIREDATE LIKE EMPLOYEE.HIREDATE ASSIGN EMPLOYEE.HIREDATE,

        JOB LIKE EMPLOYEE.JOB ASSIGN EMPLOYEE.JOB,

        EDLEVEL LIKE EMPLOYEE.EDLEVEL ASSIGN EMPLOYEE.EDLEVEL,

        SEX LIKE EMPLOYEE.SEX ASSIGN EMPLOYEE.SEX,

        BIRTHDATE LIKE EMPLOYEE.BIRTHDATE ASSIGN EMPLOYEE.BIRTHDATE,

        SALARY LIKE EMPLOYEE.SALARY ASSIGN EMPLOYEE.SALARY,

        BONUS LIKE EMPLOYEE.BONUS ASSIGN EMPLOYEE.BONUS,

        COMM LIKE EMPLOYEE.COMM ASSIGN EMPLOYEE.COMM,

        CURRENCY LIKE EMPLOYEE.CURRENCY ASSIGN EMPLOYEE.CURRENCY,

        END GROUP);

 

1.          COPY statements.   This section won’t be found in derived definitions.

COPY Employee;

COPY TYPES;

It enables LIKE definitions and ASSIGN properties, such as

FIRSTNME LIKE EMPLOYEE.FIRSTNME ASSIGN EMPLOYEE.FIRSTNME,

 

2.          Initial DEFINE statement.

DEFINE MyJSv-JSPG1 SYSTEM DATA([Not in COBOL

Jazz COPY books must include a DEFINE statement with the same name as the COPY name, otherwise an error will be reported.  This is the main function of this definition, although it also contains some information that may be used by MANASYS Jazz as you edit the program.  It is a SYSTEM definition which means that it won’t be generated into the COBOL program.  If you want actual fields in your program with this information then you can define fields within another definition, for example

DEFINE SundryData DATA(

    INPUT LIKE MyJSv-JSPG1.INPUT);

 

3.            Input Definition. The INPUT record is the program name prefixed with ”I”.   Program JSPG1 is an enquiry program, returning an EMPLOYEE record based on either the primary key or an alternate key.

 

4.          Output Definition. The OUTPUT record is the program name prefixed with “O”.

Add Service Reference Information

The Add Service Reference dialog opens with a combo that displays the list of previously-discovered services. Data for this is saved in WebServices.jzw, an XML document that is saved in your Jazz CopyLib.   As each new service is discovered, another line is added to this: -

<?xml version="1.0" encoding="utf-8"?>

<!--WebServices.jzw documents the web services used in your project-->

<!--Do not manually update this file-->

<References>

  <LastUpdated>12/04/2020 2:18:06 PM</LastUpdated>

  <LastUpdatedBy>JAZZUSR</LastUpdatedBy>

  <Reference SURL="http://localhost:9003/cics/services" RefName="MyJSv" Type="JSON" />

  <Reference SURL="http://localhost:5482/cics/services" RefName="MyWSv" Type="WSDL" />

  <Reference DURL="https://petstore.swagger.io/v2/swagger.json" SURL="http://petstore.swagger.io/v2" RefName="PtStr" Type="JSON" />

  <Reference DURL="http://www.jazzsoftware.co.nz/SOATesting/Service1.svc?wsdl" SURL="http://www.jazzsoftware.co.nz/SOATesting/Service1.svc" RefName="JZTs2" Type="WSDL" />

</References>

The services like petstore and SOATest which have been discovered from an external site, the service reference

Also, data for each specific service is saved.  For the petstore service, this is saved as PtStr.jzw: -

<Reference Updateable="False">

  <!--This documents web service PtStr at https://petstore.swagger.io/v2/swagger.json-->

  <!--Do not manually update this file-->

  <ServiceReferenceName>PtStr</ServiceReferenceName>

  <URI>https://petstore.swagger.io/v2/swagger.json</URI>

  <Type>JSON</Type>

  <Created>12/04/2020 11:54:46 AM</Created>

  <CreatedBy>JAZZUSR</CreatedBy>

  <Operation Name="/pet/{petId}/uploadImage" />

  <Operation Name="/pet" />

  <Operation Name="/pet/findByStatus" />

  <Operation Name="/pet/findByTags" />

  <Operation Name="/pet/{petId}" />

  <Operation Name="/store/order" />

  <Operation Name="/store/order/{orderId}" />

  <Operation Name="/store/inventory" />

  <Operation Name="/user/createWithArray" />

  <Operation Name="/user/createWithList" />

  <Operation Name="/user/{username}" />

  <Operation Name="/user/login" />

  <Operation Name="/user/logout" />

  <Operation Name="/user" />

</Reference>

 

Parking

Everything below is from the old UG chapter, and needs to be reviewed

Creating a Web Service Description

Resolving INVOKE ?; into code like that above is easy if the COPY book exists, but what if it doesn’t?   If

·         There is no COPY book for the selected operation, or

·         You right-click the operation name, or

·         You click [Refresh]

then Jazz opens a form from which you can create the copy book from WSDL or JSON

 

You click one of the top four buttons to locate WSDL or JSON describing the service.  Provided that this is found and it follows the appropriate standards a Jazz COPY statement like JZTst-SOATest1 will be created and inserted into the program. If you click [Edit Jazz Description] without locating any WSDL or JSON, then an empty definition will be created. You can edit the Jazz definition like any other COPY statement, and you can re-create the definition by clicking [Refresh] or right-clicking the selected operation.

 

 

Exchanging Data with SOA Objects

The point of standards-based SOA is to facilitate the use of services across a network by heterogeneous programs. From a Jazz (=COBOL) program we can use a service provided by VB, ASP.NET, C#, Java, ….  as well as services provided by other COBOL programs. In theory we shouldn’t need to know what technology the service uses, or supply any further information, all we need to know where to find the interface.

 

Yet even with our first Requester test this theory starts to be compromised. In the world of Java and ASP.NET a string variable can hold a unicode string of any length and WSDL often describes a field simply as “String”, with no maximum length.  That’s the case here, where SOATest1 receives one string, and replies with another, but the strings can be any length.  You could enter “Very long name, going on and on until I got tired of typing” into the textbox on the test site, and the ASP.NET test program would respond

            “SOATest1. Hello Very long name, going on and on until I got tired of typing. The NZ date/time is 2/02/2015 12:10:48 p.m.”

 

However the mainframe world of COBOL and PL/I has no direct equivalent of an ASP.NET string.  CHAR and VARCHAR variables have a maximum length, and we therefore need to know what the maximum lengths of the string fields are so that the Jazz program can define fields as (for example) VARCHAR(20), generating a COBOL definition

000585      03 Name.

000590         49 JZL-Name              PIC S9999 COMP-5 SYNC.

000595         49 JZD-Name              PIC X(20).

 

If the web service originates in the mainframe world of fixed-length strings then the WSDL describing the service may include a maximum length, but in other cases Jazz needs to supply a maximum length value.  For Build 13.2 Jazz simply follows the IBM practice and uses a default of 255, but a future release will prompt you for these values.

Planned Feature: selecting Maximum String Lengths.

The first time that you select the service you will be prompted to enter them. For example: -

 

After getting the maximum length of Name for the input message, the dialog will ask you for the length of the reply and the name for the output message.  Fortunately the values will be saved and you won’t need to enter them again.  If the service has several operations (our test service has two, SOATest1 and WSDLTest) you’ll give these limits for each operation in turn.

 

In later exercises you’ll see how to manage tables (arrays) which, like strings, may be of indeterminate size, and other data types that don’t easily convert between COBOL and WSDL data types.

 

We won’t have to repeat this every time that you want to access this web service. Jazz remembers that we’ve accessed a service from this URI, and next time you write INVOKE ?; in a program the combo box will already be populated, and the maximum lengths of Name and Reply will be filled in.  Also, as you and other members of your project team access other web services the URI’s of these will be added to the combo box so that it will contain all the web service names used within your project.

Selecting an operation

Web services may provide several operations, so next we have to select which one we want.  If we have just read the WSDL the operation list may look like this: -

 

Click the [+] and Service1 expands: -

 

Click this [+] and you see the actual Operations offered at this URI: -

 

NOW we can select the one we want.  We click on “SOATest1”. 

 

If we selected a service that was processed earlier then the display will omit these higher levels and look like this, so we don’t need to expand these extra levels.  We still have to select the operation that we want: -

 

Continuing our Program

We wrote INVOKE ?; and clicked [Check], causing Jazz to initiate a dialog where we discovered a web service and retrieved its interface specification.  We return to our program to find that Jazz has replaced the “?” and changed our program to this: -

*# Last Updated by IBMUSER at 18/11/2015 3:22:28 p.m.

PROGRAM WST1 CICS INSCREEN(WST1S) TRANSID(TRW1) COMMAREA(WST1C) ;

DEFINE Wrk  DATA(

    Name VARCHAR (20),

    Result VARCHAR (70));

ACCEPT (WST1S.Name);

    COPY JZTst-SOATest1;

INVOKE JZTst-SOATest1(?);

#263 E No definition found for JZTst-SOATest1: COPY inserted. Click CHECK again

SEND inscreen;

We do as the message requests and click [Check] again, and our program becomes

*# Last Updated by IBMUSER at 18/11/2015 3:22:28 p.m.

PROGRAM WST1 CICS INSCREEN(WST1S) TRANSID(TRW1) COMMAREA(WST1C) ;

DEFINE Wrk  DATA(

    Name VARCHAR (20),

    Result VARCHAR (70));

ACCEPT (WST1S.Name);

COPY JZTst-SOATest1;

INVOKE JZTst-SOATest1(ISOATest1.Name [IsVarchar]);

SEND inscreen;

 

Note these points: -

1.            The service name that we use combines the service reference name, “JZTst”, with the operation name “SOATest1”.

2.            Jazz creates a list of all Web Services used in a project – you’ll find it stored in the Jazz library as WebServices.jzw, and the list appears in various dialogs.  When you use the INVOKE ?; dialog in another program the prompt will offer the list of previously-searched URIs.  If you select the same or another operation from this URI it will also be qualified as “JZTst”.

3.            The dialog will have added an appropriate interface definition into our Jazz Program: see the COPY statement that has been inserted just ahead of the INVOKE. This is a normal COPY statement except for one thing.  You can right-click the COPY statement to see what it looks like, but any changes you make to it will be ignored.  This is an externally defined record layout, and the only way you can update it is by refreshing it, which you do by clicking [Refresh] in the Web Services Discovery dialog.

4.            You’ll see that the record definition looks something like this: -

*# Last Updated by IBMUSER at 18/11/2015 3:26:47 p.m.

*# Definition created from Web Service JZTst-SOATest1

*# Do not manually edit this definition

DEFINE JZTst-SOATest1 SYSTEM DATA(

    INPUT VARCHAR(30) VALUE 'ISOATest1',

    OUTPUT VARCHAR(30) VALUE 'OSOATest1');

DEFINE ISOATest1 SERVICE DATA(

    Name  VARCHAR(255) OPTIONAL minOccurs 0);

DEFINE OSOATest1 SERVICE DATA(

    SOATest1Result  VARCHAR(255) OPTIONAL minOccurs 0,

    Name  VARCHAR(255) OPTIONAL minOccurs 0);

Note that this is a Jazz-format definition, it is not XML. SERVICE tells Jazz everything that it needs to know in order to generate XML documents and SOAP messages when appropriate, and COBOL definitions when appropriate, and to invoke the web services correctly.

5.            Three definitions are inserted into our program for each web service operation: -

1.            The first provides a definition of the web service operation, naming the input and output messages.  Type SYSTEM means that it is available to Jazz, but not generated into COBOL.

2.            The 2nd uses the operation name prefixed with “I” to define the input message.  “Input” and “Output” means from the perspective of the service: we invoke JZTst-SOATest1 passing it a name to it, so the message ISOATest1 is input to the web service, but output from our program.

3.            Similarly the 3rd definition defines the output message.

6.            INVOKE ?; becomes INVOKE JZTst-SOATest1(?); When we click [Check] again this becomes INVOKE JZTst-SOATest1(I-SOATst-SOATest1.Name [IsVarchar]);

This is Jazz’s way of showing you that when you invoke SOATest1 you pass it an input message containing a single field, of type VARCHAR. However this may not be the actual field that we want to pass to SOATst-SOATest1. Currently our program receives the data from the screen in field WST1S.Name, and this is assigned to field WRK.Name by the ACCEPT statement, so there is no data in the parameter field yet. We either have to write an assignment statement,

I-SOATst-SOATest1.Name = WRK.Name;

or name the actual field containing the data in the parameter list. The 2nd alternative is neater, so we’ll change the INVOKE statement to

                        INVOKE SOATst-SOATest1(Wrk.Name);

Handling the Reply

We’ve now written our program to the point where it will send data to the web service, but what happens to the reply? We need to provide something to handle the service’s response. This could hardly be simpler: we just add a REPLY option.  Our INVOKE statement becomes

          INVOKE JZTst-SOATest1(Wrk.Name) REPLY(?);

We click [Check] to process the program again. As with the input data list Jazz responds with the defined parameters: -

INVOKE JZTst-SOATest1(Wrk.Name) REPLY(OSOATest1.Result [IsVarchar],

OSOATest1.Name [IsVarchar]);

As before we could write assignment statements to move these fields to the actual program fields that we want, but it’s easier to simply change these name these fields in Wrk:-

INVOKE SOATst-SOATest1(Wrk.Name) REPLY(Wrk.Result,  Wrk,Name);

 

That’s it: our program is now complete, and we are ready to compile and test it.  Here is the complete program: -

*# Last Updated by IBMUSER at 18/11/2015 3:22:28 p.m.

PROGRAM WST1 CICS INSCREEN(WST1S) TRANSID(TRW1) COMMAREA(WST1C) ;

DEFINE Wrk  DATA(

    Name VARCHAR (20),

    Result VARCHAR (70));

ACCEPT (WST1S.Name);

COPY JZTst-SOATest1;

INVOKE JZTst-SOATest1(Wrk.name) REPLY(wrk.result, wrk.name);

SEND inscreen;

 

Click [Process] and Jazz will submit this job to be compiled. We’ve already used CEDA to define program WST1, map WST1S, and transaction TRW1 into our test CICS system, so there’s only minimal CICS set-up needed.

1.            CEMT SET PROGRAM(WST1) NEWCOPY

2.            CEMT PERFORM PIPELINE(MNJZREQR) SCAN

(we defined MNZREQR as well as the provider pipeline MNJZPROV earlier.  See JazzUGSOA2.htm).

Dealing with WSDL Conversion Errors

When you discover a web service you may find that one or more of the operations aren’t converted to Jazz definitions.  If you see a message like this: -

 

There is no problem if you don’t want to use this operation, but if you want to use JazzWSDLTest then you need to create a correct Jazz definition for it.   This diagram shows what’s going on when you get or refresh a service definition: -

 

While Jazz is trying to convert the WSDL directly into a Jazz definition, the mainframe job is converting the same WSDL into COBOL definitions.  These are mostly ignored by Jazz, but if Jazz has failed to convert the WSDL we can convert them into Jazz.

 

When the message “… except for xxxx” appears the button [DFHWS2LS Layout] also appears.   Wait until the mainframe job has finished, then click this.  If there is more than one “xxxx” then choose which one you want to convert.   Jazz then retrieves the relevant COBOL layouts and converts them back into Jazz.

More Parking

description of the service it will attempt to read this descriptive information and create a Jazz description from it.  But there’s a lot that can go wrong, and this process may fail: -

INVOKE JZTst-SOATest1(?);

#402 S Error parsing WSDL. Jazz COPY not generated

#126 S Refresh the service definition to re-create JZTst-SOATest1

#263 E No definition found for JZTst-SOATest1 but COPY required or present

#263 E No definition found for JZTst-SOATest1

#246 E DEFINE xxx PARAMETERS not found. Parameters not checked

 

 

Here Jazz has located WSDL at the URI that you gave, and it is about to create Jazz-format DEFINE statements describing the data, and submit a job to create the objects (.wsdl and .wsbind files in the HFS) that you need for your CICS system to invoke this service.  This form functions like the usual Jazz Process form allowing you to interrupt the process at each of its stages.  Normally you’ll simply click [Submit], and all three stages will run and a zOS job will be submitted.

 

Even if you click [Close] Jazz will continue with the first step, reading the WSDL and creating Jazz data definitions from it.  As it creates these it may encounter elements that lack some of the information required by COBOL (and hence by Jazz) such as the lengths of character strings. Let me explain.