Creating a Client Interface for a MANASYS Jazz Web Service

This feature was released in build 16.1.238 for initial testing.
Build 16.2 introduced client support for
    Add and Delete functions (Update was supported with 16.1)
    Messages with multiple records (Max > 1)
    Services returning data from VSAM (previously only DB2)
    Related Fields: .
 

This is a work-in-progress
See Road Map for its current status, and proposed future development

Contents

Creating a Client Interface for a MANASYS Jazz Web Service. 1

Introduction. 1

Prerequisites. 1

Revision: Creating a JSON Web Service. 1

Configuration and Set Up. 1

Step 1.  Create an Interface Project 1

Step 2 (Optional).  Create Projects for Test Objects. 1

Step 3.  Configure Jazz – Client Tab. 1

Step 4.  Configure Jazz – Workbench Tab. 1

Creating a Client Interface. 1

Step 1.  Locating JSON and Creating the Message Descriptions. 1

Step2.  Creating the Client Interface. 1

Server-side and Client-Side Validation. 1

When do you Need to Re-create a Client Interface?. 1

Using a Client Interface. 1

Getting Started – Locate or Create a Suitable Project 1

Creating a Client Form.. 1

Intellisense. 1

Source Code. 1

Form Logic - Properties. 1

Form Logic – Methods. 1

Managing Scrolling. 1

Update, Delete, and Add. 1

Clear and Close. 1

Client Projects with Multiple Forms. 1

Sample Clients. 1

Appendices. 1

Programs used as Examples. 1

Returning Multiple Records. 1

Logic used when Max > 1. 1

Measuring Response Time. 1

Browsecount 1

Jazz Message Definitions. 1

Messages – COBOL, JSON, C#, and Binding. 1

Request message as JSON. 1

RequestJSPG2.cs. 1

ResponseJSPG2.cs. 1

Response JSPG2A.. 1

Understanding the Client Interface. 1

1.     Private. 1

2.     Key Properties. 1

3.     I/O Data. 1

4.     Output 1

5.     Value properties. 1

3.     Functions. 1

4.     Standard Response Properties. 1

5.     RequestResponse. 1

6.     Methods. 1

7.     Routines. 1

Road Map. 1

 

Introduction

In minutes MANASYS Jazz can generate a CICS Web Service that can perform enquiry and/or update from one or several VSAM files or DB2 database tables, generating hundreds of lines of COBOL logic and also the necessary supporting objects (WSDL or JSON, and the binding objects that convert between JSON or WSDL and COBOL).  The COBOL logic will validate incoming data and implement the rules of the web service such as “Update must follow an enquiry”. 

Both REST (JSON) and SOAP (WSDL) services can immediately be tested with utilities like PostMan and ReadyAPI, but even though a ReadyAPI test can be created in minutes it was far from easy to develop a client-side program to interact with a CICS Web Service, especially if you want client-side validation to avoid unnecessary web service requests.  However MANASYS Jazz can now generate an interface object for JSON web services that makes client development very easy.  Click here to see a short video introducing this process.   The interface exposes properties and methods encapsulating the rules of the service:  for example Employee.Sex must be M or F, Employee.Empno must be numeric, Update must follow an Enquiry and must return the CheckSum value from the Enquiry, and so on.  Clients need only refer to the properties and methods provided by the interface object to obey the rules.  Agile development is now easy: should the web service change, just re-generate the interface object to reflect new rules and data.  The Client Program (which you write) will need changes only to reflect new functions and data provided by the new version of the service.

In the diagram above, Jazz will have generated the service MyJSv-JSPG2 as a COBOL program on the “mainframe”, and the interface JSPG2Client as a C# object in your MyJSv interfaces project.  Why C#?  By targeting C# and .NET Core the interface can be used not only in Windows, but also with Linux, Android, IOS, and perhaps other operating systems.  You will write the actual client-side logic in the language of your choice – VB.NET, C#, Java, … for whatever client environment you are using (Windows form, Web page, mobile app…).

As later programs are generated their interfaces are added into the interface project for the service: -

This Users’ Guide chapter shows you how to create these client-side interfaces.

Note: this chapter uses various programs within Service MyJSv for its examples.  Programs have names starting with “JS”, so when you see “JSPG2” or “MyJSv” written, including as parts of longer words, mentally substitute your own names.  For a full list of the programs that might have been used in demonstrations, see Programs used as Examples.

Prerequisites

Web Service Clients like Interface JSPG2Client in the diagram above are delivered as C# projects. You need to have Visual Studio 2019 16.4 or later, and .Net Core 3.1 SDK or later.

You need to be using MANASYS Jazz version 3.16.1.239 or later.

This facility is only available for JSON (=REST) web services.  It is not available for WSDL (=SOAP) services.

Revision: Creating a JSON Web Service

Jazz web service programs like JSPG1 and JSPG2 can be quickly generated from a Jazz-format definition data definition.  In this example we’re going to create program JSPG2 to update the Employee table from IBM’s DB2 Sample database.  This definition was created from the New/Data/Import from SQL (select table EMPLOYEE) and then editing the definition to add extra information such as validity rules.  Here is the definition Employee.jzc, with highlighting to show my editing changes: -

*# Last Updated by JAZZUSR at 31/08/2020 1:33:28 PM

*# Created from Table:EMPLOYEE, Schema:ROBERTBW10, Database:Sample by JazzUser at 26/03/2019 4:25:46 PM

COPY Department;

DEFINE EMPLOYEE SQL DATA(   

    EMPNO CHAR(6) PIC '999999' REQUIRED KEY,

    FIRSTNME VARCHAR(12) REQUIRED,

    MIDINIT CHAR (1),

    LASTNAME VARCHAR(15) REQUIRED,

    WORKDEPT CHAR(3) CAPS DKEY 'XEMP2' EXISTS DEPARTMENT.DEPTNO,

    PHONENO CHAR(4) PIC '9999',

    HIREDATE DATE,

    JOB CHAR(8),

    EDLEVEL SMALLINT REQUIRED,

    SEX CHAR(1) CAPS CODES(M:Male, F:Female),

    BIRTHDATE DATE,

    SALARY MONEY(9,2) MIN 0,

    BONUS MONEY(9,2) MIN 0,

    COMM MONEY(9,2) MIN 0,

    CURRENCY CHAR(3),

    DEPTMGR BOOLEAN);

Editing changes were: -

·         To SQL EMPNO and PHONENO were simply CHAR fields, but they were supposed to be character-format positive integers.  SQL doesn’t support a PICTURE data type, but Jazz allows PIC to be given as a property.  Now any attempt to assign a value other than 000000 to 999999 to EMPNO will be detected and reported by ACCEPT.

·         WORKDEPT is a foreign key.  EXISTS ensures that non-null values must be current values of the primary key of DEPARTMENT.  By also adding CAPS MANASYS ensures that values received as (for example) “d11” will be converted to “D11”.  We strongly recommend that any KEY, DKEY, or UKEY field use CAPS to avoid errors and ambiguity.

·         SEX can have any value as far as SQL is concerned, but the actual data rules are that it must be M meaning Male, or F meaning Female.  Adding CODES(M:Male, F:Female) specifies this.  As with a key value, CAPS is recommended.

·         Import from SQL rendered SALARY, BONUS, and COMM as DECIMAL.  Changing DECIMAL to MONEY will display them with $, and MIN 0 ensures that they can’t be -ve.

·         I had added CURRENCY and DEPTMGR to IBM’s definition of the EMPLOYEE table.  CURRENCY was added to test that MANASYS Jazz could handle COBOL reserved words as SQL column names, and DEPTMGR was added to test that a typical COBOL “Boolean” value – a CHAR(1) field with possible values ‘Y’ or ‘N’ – would be handled correctly as a C# Boolean field with values True or False.

With Employee.jzc properly defined, the dialog New/Logic/Web service, with values like this, creates program JSPG2 to update the Employee table: - 

This dialog creates a Jazz definition of the request and response messages, and of the logic of the program (in this case a single-table update program with CICS-style pseudo-locking).    Here is the message definition for JSPG2.   Here is a copy of program JSPG2 as Jazz, and as COBOL.

A web service request/response is a relatively slow process, in my test environment taking about 3 seconds whatever the size of the web service message, so it makes sense to return as much as possible each time.  Employee is defined with a duplicate key (WorkDept), and with my test data there were 14 records with WorkDept = D11, so JSPG2A was generated like JSPG2 except that I set Max >1.  If this were a production situation I’d set max to 14 or greater.  For my testing I set Max=6 to test that the generated logic handled this, automatically getting the next 6 (and the next) as you scrolled forward.  The takeaway: set Max as large as necessary, but it doesn’t have to be the maximum possible.  See the appendix Returning Multiple Records for more information.

The process is completed by compiling the COBOL, and generating the binding objects: the JSON description of the input and output messages, and WSBIND to convert these from and to COBOL.  With Jazz configured for zOS this happens automatically as JCL is created and submitted to compile the COBOL and then perform further steps to create the binding objects.  With Jazz configured for Micro Focus Enterprise Developer there are a series of dialog steps to achieve the same effect.  This is covered elsewhere: see here for zOS, and here for MFED

Statistics so far:  Employee.jzc is 18 lines of code, 9 of which we edited.  From this we generated 54 lines of Jazz message definition (editable, but we didn’t in this case), and 28 lines of Jazz program logic (which again, we didn’t edit). This became 2500 lines of COBOL, 320 lines of JSON conforming to the Swagger standard and the binding objects to convert between COBOL and JSON.  All of this compiles cleanly first time, and we have a running web service that can be tested with utilities such as ReadyAPI.

Now to get back to the real point of this Users’ Guide chapter, which is creating a client interface to make using such web services easy.  First we must configure MANASYS Jazz for Client Interfaces.

Configuration and Set Up

We must first create an empty ASP.NET Core Web Application.  Then we will configure Jazz so it knows where to find this, so that it can create and update objects within it.

Step 1.  Create an Interface Project

1.    Open Visual Studio, create a new project. =>

2.    Select template ASP.NET Core Web Application, click [Next] =>

3.    Name the project MyJSv (or your web service name, see above).   
Note the location (e.g. copy it to the clipboard).  For me, this was C:\Users\Robertbw10\source\repos
Check “Place solution and project in the same directory”. Click [Create] =>

4.    Choose a template.  I’ve chosen Empty.  Click [Create] =>

Visual Studio creates the project and opens on an initial screen.  Solution explorer shows

 

5.    The generated interface is going to include the line
using Newtonsoft.Json;

To make this valid in project MyJSv, click menu Tools > Nuget Package Manager > Manage NuGet Packages for Solution.

Select the Browse Tab.   If Newtonsoft.Json is not already shown in this tab, enter Newtonsoft.json and click search

Click this.  It appears to the right. 

Click [  ] Project and then Install.   Click [OK] when asked.

Step 2 (Optional).  Create Projects for Test Objects

This is a planned feature, it is not implemented yet.

As well as the interface itself (the middle object in the diagram above) it is intended that Jazz will create template objects that will use the interface objects if you check the relevant Web or Windows checkbox (the left object in the diagram).  These template objects are basic Windows or Web programs that invoke the interface to use the web service: they are unlikely to appear or do exactly what you want, but they will have some code that you can adapt.  Template objects are usually created into separate projects, with default names MyJSvCS, MyJSvVB, MyJSvJV, etc.   C# objects can be created directly into the interface project.

If you are going to use this feature, then you need to identify the target projects before Jazz generates objects into them.  If necessary, create new VB and Java projects with appropriate templates.  Add a reference to the MyJSv project to these projects.

Step 3.  Configure Jazz – Client Tab

Click [Configure], click the Client tab. Identify the full path to the project file created above where the MyJSv (or your name) project has been created.  For example, C:\Users\Robertbw10\source\repos\MyJSv.

If you want template objects check the relevant checkboxes, and set or locate the relevant project (not necessary for C#).  Close the Configure form.

Step 4.  Configure Jazz – Workbench Tab

Interface generation uses a number of C# templates, with names @xxxx.cs.   If you have installed MANASYS Jazz before the Client Interface feature was developed then these objects will not have been included in your previous downloads.  If so, or you have been advised by your MANASYS support that there is an updated version, you should ensure that you have the latest version.

 

With WebAPI defined, return to the Workbench tab, and click [Initialize Project].   Select all the @xxxx.cs objects.   The current list is: -

@Add.cs

@BoolValue.cs

@DateValue.cs

@Delete.cs

@InList.cs

@IsBool.cs

@IsDate.cs
@IsFloat.cs
@IsInt.cs
@IsNoLongerThan.cs
@JazzClient.cs
@Method.cs

@ReadNoScroll.cs

@ReadScroll.cs

@RequestResponse.cs
@Update.cs

With the objects selected, click [Open].  This will copy them to your programs folder, so that they can be copied to the interface project created in Step 1. 

Creating a Client Interface

To create an interface, open the web service program for which you want to create an interface.  If it is a JSON web service, the button after [Configure] will be enabled and be labelled [Client].  You will need to have completed the development of the web service, not just generating COBOL but also compiling the COBOL and creating the Binding File and JSON message descriptions.  Click [Process] to create the latest version of your program, then depending on your test environment: -

·         zOS:  [Process] submits the job for remote compilation.  For a web service the job includes post-compilation steps to generate the JSON definitions and the Binding file (a program which converts between COBOL ó JSON Layouts).  The JSON layouts should have been copied back to your local (Windows) environment.

·         Micro Focus:  [Process] creates COBOL, and then passes control to the Micro Focus COBOL project.  Compile the COBOL, then create the web service interface and binding objects as described here, particularly the section headed Prepare Web Services for Testing.  If you are re-creating a client interface after modifying a program, make sure that you’re using the most recent version of the binding objects by deleting and recreating the service interface (.svi) and associated objects (.wsbind, and .json).  See When do you Need to Re-create a Client Interface? for more information.

You will probably have tested that your service works to at least a rudimentary level with a Postman or ReadyAPI test. 

Click [Client] and the Web Service Client Interface dialog appears: -

WebAPI is set with Configure/Client (in Step 3.  Configure Jazz), and is the location of your C# project.  Service and program name come from the PROGRAM statement.  The Service name must be the same as the last level of WebApi. 

If you have already created this interface check [  ] Replace to re-create it.   Local JSON will always be checked: the checkbox is provided for future development, which will allow interfaces to be created for externally-developed web services.

Click [Create Interface].  Jazz will create a C# interface object called xxxxClient.cs, e.g. JSPG2Client.cs, and if you have checked [  ] Web or [  ] Windows it will create further objects as “templates” for you to adapt that will use the interface.  Here we’ve checked [ü] Windows, so a Windows form named TestJSPG2.cs will be created into your C# project.   Further options (VB.Net, Java, etc) will be developed.   Planned, not yet available.

If errors are detected then messages are reported as Jazz Error messages, following the Program statement: -

Step 1.  Locating JSON and Creating the Message Descriptions.

When [Create Interface] is clicked, Jazz first locates the JSON descriptions of the web service.  When you created program JSPG2 (including the steps following Jazz, when the COBOL program was compiled and the support objects (“Binding file”) were created), three .json files should have been written into your project file.  For example, my project file (which I set with [Configure]) is C:\tutorials\TstSQL.   For program JSPG2 the three .json files are: -

·         JSPG2.json           This is created directly by Jazz when you generated program JSPG2: it is a Swagger definition that defines the service and has references to the message formats (schemas) IJSPG2 and OJSPG2, which may not exist yet.

·         JSPG2I.json          This describes the Input (Request) message.  It is created later, by either ZOS or Micro Focus.  If created by ZOS it will have originally been created on a mainframe, and should have been automatically copied back to your project file.

·         JSPG2O.json        This describes the Output (Response) message.  Like JSPG2 it is created later.

From the Swagger definition Jazz extracts path information (request type – post, put, etc, and path, e.g. http://localhost:9003/cics/services/JSPG2), and references to the schemas for the input and output messages.  The input and output schemas are vital as they describe the format of the messages sent to and from the web service.

If these files can’t be located then message #559 will be produced.  To correct the problem, first check that all the steps after producing COBOL – compile the COBOL, produce binding file and JSON   have been completed (e.g. by testing the service with a utility like Postman or ReadyAPI).   If you can run such a test then JSON has been produced, although the JSON may still be only on the mainframe.   Locate this JSON manually, and copy it to your project folder.

Jazz then creates the message definitions: -

RequestJSPG2.cs      Created from the input message, IJSPG2, this is the actual structure of the request message. 

ResponseJSPG2.cs   Created from the output message, OJSPG2, this is the actual structure of the response message.

If you were to examine your C# interface project, it would now look like this except for the client object (JSPG2Client.cs) which will be created in the next step.

Step 1 has created the Request and Response objects, like the examples below.  Next Jazz creates the interface object, JSPG2Client. 

Step2.  Creating the Client Interface

An object like JSPG2Client provides one or more methods to communicate with the web service.   Program JSPG2 requires at least four methods, Enquiry, Update, Add, and Delete, corresponding to the possible values of Function, and there are also ReadNext, ReadLast, ReadPrev and ReadFirst methods because the Enquiry offers a scrolling option if you read records by the duplicate key, WorkDept.  Other clients might include Logon, Logoff, New Order, Process Order etc.

The process starts by reading a template, @JazzClient.cs, into memory, substituting values for @Service (=MyJSv) and @Program(=JSPG2), and removing markers like @Private after pointers are set to the preceding lines.  The Client object is then generated based on all the information that is available to program JSPG2.  You can learn more about it at Understanding the Client Interface.

Server-side and Client-Side Validation

The purpose of a client interface like JSPG2Client.cs is to make it much easier for client programs to interface with the web service, and to provide local validation so that errors are detected instantly rather than with the delay inherent in a Request/Response cycle.  However local and remote validation rules may differ:

1.    Validation requiring further I/O, such as an EXISTS property, is not checked locally.  For example, Employee.Workdept is defined

    WORKDEPT CHAR(3) CAPS DKEY 'XEMP2' EXISTS DEPARTMENT.DEPTNO,

To be valid any value entered for WorkDept must exist as a value of DEPARTMENT.DEPTNO, the primary key of the DEPARTMENT table.   This is not checked within JSPG2Client.  There would be no point in doing this: it can only be checked by sending a request to a web service, incurring the response delay that local validation is supposed to prevent.

2.    CHECKR properties are defined in the record definition to specify Check Routines, which are routines (paragraphs or subprograms) that check particular fields, for example a bank account, social security number, etc.  The web service knows their names and interface rules, but not their internal logic, and they may be written in COBOL or any language that can be called from a COBOL program. A Check Routine might even require server-side I/O, for example looking up reference tables.  Like EXISTS, these are not checked locally.

Future development: it should be possible to write your own local routines, for example to check that a social security number has the correct format, and use these in an interface. 

3.    Some local validation may follow different rules because formats are different, or COBOL and C# follow different rules.  Particular examples:

a.           A Jazz BOOLEAN field is usually a CHAR(1) with ‘Y’ meaning ‘true’ and not ‘Y’ meaning ‘false’.  The interface will render these as ‘true’ and ‘false’, and expect input as “t’ or ‘f’ (which will become “true” or “false”, but be sent to the service as Y or N).

b.           DATE fields are transmitted in a standard form (Integer, format yyyymmdd), whatever the culture settings at either end, but are displayed and managed with your local culture settings.  For example, BirthDate is transmitted as 19560527, but with New Zealand culture settings will be displayed and edited as 27/05/1956.  With U.S. settings it would be displayed and edited as 5/27/1956.

For these reasons, and also because the service cannot guarantee that the message it receives has come from the web service client interface, request messages are fully validated when they are processed.  With good client-side validation most of the possible errors will have been prevented, but the cost of repeated validation is a small price to pay for the assurance it provides.  Should an error be detected in the service it will be reported in the returned Error value.

When do you Need to Re-create a Client Interface?

If you have modified your program in a way that doesn’t change the message formats or operations supported by the service, then you can generate and compile the COBOL program but you do not need to re-create the client interface.  For example, minor changes to logic like a different message, or a changed calculation, will have no effect on the message formats, and you can test your new program with its client without re-creating the interface.  However if you’ve selected a list of fields to be sent in the response and you change this list, or if you add or remove a method (Update, Add, Delete, etc) compared to the previous message, then you’ll need to regenerate the interface.

I generated program JSPG2 to return 1 EMPLOYEE record, and program JSPG2A to return 6.   The difference between 1 and 6 means that for JSPG2A the EMPLOYEE data is returned in an array, and so the interfaces are different.  However client-side arrays are more like lists than a repeating set of identical structures that a COBOL programmer understands as an array. Because EMPLOYEE data is returned as an array for JSPG2A, but not for JSPG2 (even though the COBOL record structure is defined with OCCURS 1), JSPG2 and JSPG2A require different interfaces.  The interface need not be re-created if JSPG2A is changed to return a different number, provided that it is > 1.

Using a Client Interface

The section above, Creating a Client Interface, dealt with creating the middle section of this diagram.   Creating this is simply a matter of clicking [Client] and then [Create Interface] from the Jazz Workbench with the program that created the web service (right section, “Mainframe”).  If changes are made to the service you can re-generate the interface.

To use the interface you’ll develop a client – a Windows Form, a Web page, or a mobile App – that communicates with the web service through the interface.  This client might be developed in C#, Java, VB, or other languages. This is the left part of this diagram.

 

Clients will communicate with the interface through properties and methods, which can be discovered in the usual way.  This section describes how you can write such a client: TestJSPG2 is a Windows form that uses JSPG2Client to communicate with the web service.  This section shows how you would write such a client, using Visual Studio.

It is planned that MANASYS will generate prototype clients, like the Windows form used in this example.  These are unlikely to be anything more than a code template, from which you can extract useful code snippets.   A real client may invoke other web services, access local data, or services like the client’s current GPS location.

Getting Started – Locate or Create a Suitable Project

Client objects are created within a suitable project – for example, if you want to create a C# Windows client, then you must have a C# Windows project.  For a VB Windows Client you’ll need a VB Windows project, and so on.  If such a project doesn’t exist, you can create a new project.

To create a suitable C# Windows Project: -

1.    Open Visual Studio, select New Project, and choose a suitable template.  I chose Windows Forms App (.NET Core).  Click [Next]

2.    On the next form

a.    give the project a name (I used “MyJSvClientTests”),

b.    optionally check [  ] Place solution and Project in the same directory (recommended), and

c.     click [Create].   A project is created with these objects: -

3.    Right-click Solution ‘MyJSvClientTests’, and select Add/Existing Project.  A Windows Explorer opens showing you your projects.  Click on folder MyJSv, and then when that folder opens, click on MyJSv.csproj and then click [Open] : -

 

The project now looks like this: -

4.    (Optional Step).  Rename Form1 to something with more meaning.  I renamed it to JSPG2Test: -

a.           Right-click Form1.cs, click Rename

b.           Change “Form1” to “JSPG2Test”

c.           Reply [Yes] to the message “Would you also like to perform a rename in this project to all references to the code element ‘Form1’?

d.           Open the form JSPG2Test and change its Text property from Form1 to JSPG2Test to be consistent with its object name

 

Now we want to add controls to the form: buttons to invoke interface methods, labels and textboxes to display data.   Before we can do any of this, we have to add a reference so that we can refer to the interface JSPG2Client in project MyJSv.

 

5.    Right-click the Project (NOT the Solution) MyJSvClientTests and select Project Reference.   Because we have already included this project within our Solution, it is the first option: -

Click this checkbox.

6.  Now we need to instantiate an interface object within our form. Edit the code for form JSPG2Test (if it is not already open in Visual Studio, right-click JSPG2Test.cs in Solution Explorer, and click View Code).  Add
   static JSPG2Client Jspg2Client = new JSPG2Client();
where shown in the code below.  Visual Studio adds
   using MyJSv;
at the top, because it is now necessary. 

7.  We also add

bool EditMode = true;

      The reason for this will be clear shortly.

The C# code for our form now looks like this: -

using MyJSv;

using System.Windows.Forms;

 

namespace MyJSvClientTests

{

    public partial class JSPG2Test : Form

    {

        static JSPG2Client Jspg2Client = new JSPG2Client();

        bool EditMode = true;

        public JSPG2Test()

        {

            InitializeComponent();

        }

    }

}

Creating a Client Form

Now that we’ve created a suitable form object, JSPG2Test, and instantiated the interface object JSPG2Client as Jspg2Client  (same name, different capitalization), we’re ready to design the form (or web page or app or …) by adding controls (labels, textboxes, buttons) to communicate with Jspg2Client properties and methods.  As you develop the form, you’ll develop the form’s logic, described in the next section.   In reality you’ll flip-flop between these two sections, but it’s easier to describe appearance and Form Logic separately.

Here is a form that I’ve created to test and demonstrate the interface: -

I’ve created

·         label fields lblError, lblBrowseCount and lblReturnCode to display various output fields returned by the service,

·         textboxes for fields that can be entered by users and passed to the web service and also returned from the service.  I arranged the fields used for access (EMPNO, WORKDEPT, and SKIP) at the top, and highlighted the two key fields.

·         Access by WORKDEPT might return several values, for example WORKDEPT=D11 corresponds to ~ 14 records in my test data.  The form needs scrolling commands as shown to manage this, arranged in a Groupbox so that the control group can be displayed or not depending on whether scrolling is relevant.

·         lblSex to display the value of the Sex code,

·         lblHttpResponse to display response header information, and lblRawResponse to display the response if the request fails.

·         a series of buttons for the methods that the interface supports, plus [Clear] and [Close].  

This form uses almost all of the data and methods available, but in a real situation you might use only some of the interface’s fields and methods. As well as the buttons like btnEnquire that invoke interface methods, [Clear] empties the form controls, and [Close] closes it.

How do you know what data (properties) and methods (operations) are available?   You can find out from Intellisense, or from the source code.

Intellisense

Within the logic of a control write the name of the service interface (Jspg2Client) followed by a period.  This name comes from
           
static JSPG2Client Jspg2Client = new JSPG2Client();

that we wrote above.  Thus we double-click a control, and write “Jspg2client.” in its event logic:-
        private void txtEmpno_TextChanged(object sender, EventArgs e)

        {

            {

                Jspg2Client.

            }

        }

As we type the “.” Intellisense responds by showing you a list of properties and methods in the interface: -

Source Code

The source code of the service interface provides useful data.

1.    A few lines from the beginning you’ll find a definition of struct SetByUser. This provides a list of all the fields that can be changed by the client: these should become textboxes.   I have named my textboxes txtXxxx, e.g. txtEmpno, and placed a label ahead of them with their name (EMPNO).

2.    A little further down there is a comment
     
// Key Properties - fields used by methods to access records
The following properties are particularly important: they must all be present in your client program, as they are used to tell the methods which records you want to work with.  For JSPG2Client there is a field called Skip used to control scrolling, and two fields EMPNO and WORKDEPT.  EMPNO is the primary key of EMPLOYEE, and WORKDEPT is a duplicate key.  Skip is used when you access the table by WORKDEPT, providing an ability to handle multiple records with scrolling.

3.    Next is a comment
     
//  I/O Data - non-key fields that may be set for update and add, will be set in response
These properties are general non-key fields that the client might use, and might change.  Like the key properties, they should become textboxes if you want them.

4.    Coded fields and _Value properties.    Some fields in the web service have been defined as codes: for example SEX is defined: -

SEX CHAR(1) CAPS CODES(M:Male, F:Female),

The value which you can enter in the text box is the code – “M” or “F”.   Because SEX is defined with codes, a readonly property SEX_Value is created which will contain “Male” or “Female”.

Next there are output fields
     
//  Output data - readonly properties that are set from response, e.g. JZ_Error
You should put these into labels, not textboxes, because the client can’t change their value.  Of these, Error is particularly important.  If any errors are detected then text will be returned in this field, and from a normal response a message like SQL UPDATE/INSERT SUCCESSFUL will be displayed.  The fields JZ_Employee_BrowseCount and JZ_Employee_Return code are useful to control scrolling. Return Code is another example of a coded field: it is defined
    ReturnCode CHAR(1) CAPS CODES(' ':'    ',W:Warning,E:Error,S:'Serious Error',T:'Terminal Error',
                       A:Absent,C:Changed,D:Deleted,F:First,I:Inserted, L:Last, N:Nth,U:Unique));

and there is a ReturnCode_Value property in case you want to display “Absent”, etc.

5.    Following the output fields are the methods
     
//  Methods.  Usually related to Function, e.g. Function CHAR(1) CAPS CODES(E:Enquiry, U:Update, A:Add, D:Delete) will have
   //      Enquiry, Update, Add, and Delete methods

This section contains code for each method, like
     
public bool Enquiry(string PSkip = null,string PEMPNO = null,string PWORKDEPT = null)
and the code to implement this method.  You should not need to be concerned with this implementation, but you will need to put a Button in your client for each method that you want to use, and write appropriate code to invoke the method.  We’ll see how to do this later.

Form Logic - Properties

Double-click a TextBox and a TextChanged handler is added.  Using Intellisence we can select a Key or I/O property of the interface, and complete the statement by assigning the textbox’s text value to this property
        private void txtEmpno_TextChanged(object sender, System.EventArgs e)

        {

            Jspg2Client.EMPNO = txtEmpno.Text;

      }

As values are typed into the textbox they are validated according to the rules that have been built into the set option for the Jspg2Client property.  You will remember that EMPNO is numeric, and has range 0 to 999999.   Provided that the value entered obeys this rule the assignment will accept the value, but if the value is invalid it will be rejected and the interface sets output fields Error and a return code, so we write code like this. The two lines setting lblError.text and lblReturnCode.text will occur many times in the client, so they’re put into a routine: -

        private void txtEmpno_TextChanged(object sender, EventArgs e)

        {  

            if (EditMode)

            {

                Jspg2Client.EMPNO = txtEmpno.Text;

                ShowResponse();

            }

        }

        private void ShowResponse()

        {

            lblError.Text = Jspg2Client.Error;

            lblReturnCode.Text = Jspg2Client.JZ_Employee_ReturnCode + ":" + Jspg2Client.JZ_Employee_ReturnCode_Value;

        }

txtEmpno_TextChanged will be invoked whenever we key a value into txtEmpno.Text, so if we attempt to enter a non-numeric character we’ll immediately get the error message and return code displayed.  However txtEmpno_TextChanged is also triggered when a value is returned from an Enquiry (or other) method.  We don’t want this, so an if condition is added so that the code is only executed when EditMode is true: -

        private void txtEmpno_TextChanged(object sender, EventArgs e)

        {  

            if (EditMode)

            {

                Jspg2Client.EMPNO = txtEmpno.Text;

                ShowResponse();

            }

        }

We should write similar code for all of the textboxes.

Form Logic – Methods

Double-click a button like [Enquiry] and a Click handler is added:

        private void btnEnquiry_Click(object sender, EventArgs e)

        {

        }

We write code here to invoke the interface’s Enquiry method, and handle its response.  We start by writing a reference to the interface, and selecting the Enquiry method.  Intellisense shows us the parameters that the method requires.

Note also that interface methods are functions returning True or False, as they’re designed to be written as conditions of an IF statement. We add this logic to invoke Jspg2Client.Enquiry: -
        private void btnEnquiry_Click(object sender, EventArgs e)

        {

            if (Jspg2Client.Enquiry(txtSkip.Text, txtEmpno.Text, txtWorkdept.Text))

            {

                HandleValidResponse();

            }

            else

            {

                ShowResponse();

            }

        }

If there is a problem then the method returns False and only the Error and Return Code properties.  However, if the interface request succeeds a response is received with data in all the interface’s properties, so we execute HandleValidResponse to copy the data from these to our client’s controls like txtEMPNO.  All of the methods will have the same action on return, so we change this to

        private void btnEnquiry_Click(object sender, EventArgs e)

        {

            HandleResponse(Jspg2Client.Enquiry(txtSkip.Text, txtEmpno.Text, txtWorkdept.Text));

        }

        private void HandleResponse(bool Method)

        {

            if (Method)

            {

                HandleValidResponse();

            }

            else

            {

                ShowResponse();

            }

        }

If there is no need to handle scrolling, HandleValidResponse is just this: -

        private void HandleValidResponse()

        {

            SetFormValues();

        }

SetFormValues simply assigns all the interface properties to corresponding form controls. 
        private void SetFormValues()

        {

            EditMode = false;

            lblError.Text = Jspg2Client.Error;

            lblBrowseCount.Text = Jspg2Client.JZ_Employee_BrowseCount;

            lblReturnCode.Text = Jspg2Client.JZ_Employee_ReturnCode + ":" + Jspg2Client.JZ_Employee_ReturnCode_Value;

            txtEmpno.Text = Jspg2Client.EMPNO;

            txtWorkdept.Text = Jspg2Client.WORKDEPT;

            txtSkip.Text = Jspg2Client.Skip;

            txtFirstNme.Text = Jspg2Client.FIRSTNME;

            txtMidInit.Text = Jspg2Client.MIDINIT;

            txtLastName.Text = Jspg2Client.LASTNAME;

            txtPhoneNo.Text = Jspg2Client.PHONENO;

            txtHireDate.Text = Jspg2Client.HIREDATE;

            txtJob.Text = Jspg2Client.JOB;

            txtEdlevel.Text = Jspg2Client.EDLEVEL;

            txtSex.Text = Jspg2Client.SEX;

            lblSex.Text = Jspg2Client.SEX_Value;

            txtBirthDate.Text = Jspg2Client.BIRTHDATE;

            txtSalary.Text = Jspg2Client.SALARY;

            txtBonus.Text = Jspg2Client.BONUS;

            txtComm.Text = Jspg2Client.COMM;

            txtCurrency.Text = Jspg2Client.CURRENCY;

            txtDeptMgr.Text = Jspg2Client.DEPTMGR;

            EditMode = true;

        }

It is written as a subroutine as it will be used for other methods.   Note that it starts by setting EditMode = false; and concludes with EditMode = true; so that the assignments don’t execute the code in the TextChanged handlers.  This would not only be pointless but could have some undesirable side effects such as recording the field as Changed (= set by user) meaning that it will be included in a following Update.

Managing Scrolling

Program JSPG2 retrieves Employee records using either Employee’s primary key, EMPNO, or WORKDEPT.  EMPNO may retrieve zero or 1 record, WORKDEPT may retrieve zero or many records.   To handle scrolling I’ve placed buttons and the Skip textbox on the form within a groupbox: -

When the enquiry uses the duplicate key, WORKDEPT, these scrolling controls will appear if there is more than one Employee for this WORKDEPT value, and the scrolling buttons will be active if there are more records in the Next or Previous direction.  Two output fields are important for controlling scrolling: -

·         JZ-Employee-BrowseCount is set to 0 for access by unique key (EMPNO), and to the number of records that could be retrieved for non-unique access (WORKDEPT).  We do not want the scrolling controls if BrowseCount is 0 or 1.

·         If scrolling applies, then the return code, defined as

    JZ-Employee-ReturnCode CHAR(1) CAPS CODES(' ':'    ',W:Warning,E:Error,S:'Serious Error',T:'Terminal Error',
                       A:Absent,C:Changed,D:Deleted,F:First,I:Inserted, L:Last, N:Nth,U:Unique));

can tell us whether where at the beginning or end of the scrolling list.  For ReturnCode F (First) we don’t want the Previous [ < ] and First [ << ] buttons active, for Return code L (Last) we don’t want Next [ > ] or Last [ >> ].

Note 1.   Field names in Jazz or COBOL that have hyphens will have underscores in C# and other client languages.  Thus these fields are called JZ_Employee_BrowseCount and JZ_Employee_ReturnCode in C#.

Note 2.  BrowseCount is calculated differently for SQL (=DB/2 etc.) and VSAM.   See Browsecount.

Note 3.  It is a bad idea to use a scroll bar with a web service.  Dragging a scroll box causes a flurry of request/responses to be sent to/from the web service).

We’ll need code to be executed with Enquiry to control whether we see the scrolling commands, and whether the Next or Previous buttons are active.   But the scrolling  buttons, also need this code, so this logic is put into HandleValidResponse: -

        private void HandleValidResponse()

        {

            int BrowseCount;

            int.TryParse(Jspg2Client.JZ_Employee_BrowseCount, out BrowseCount);

            if (BrowseCount < 2)

            {

                gbxScroll.Visible = false;

            }

            else

            {

                gbxScroll.Visible = true;

                if (Jspg2Client.JZ_Employee_ReturnCode == "F")

                {

                    btnPrev.Enabled = false;

                    btnFirst.Enabled = false;

                }

                else

                {

                    btnPrev.Enabled = true;

                    btnFirst.Enabled = true;

                }

                if (Jspg2Client.JZ_Employee_ReturnCode == "L")

                {

                    btnNext.Enabled = false;

                    btnLast.Enabled = false;

                }

                else

                {

                    btnNext.Enabled = true;

                    btnLast.Enabled = true;

                }

            }

            SetFormValues();

        }

 

Because this web service may require scrolling, the interface has been generated with ReadNext, ReadLast, ReadFirst and ReadPrev methods.  IntelliSense discovers these, and we add methods like this: -

        private void btnNext_Click(object sender, EventArgs e)

        {

            HandleResponse(Jspg2Client.ReadNext(txtSkip.Text));          

        }

        private void btnPrev_Click(object sender, EventArgs e)

        {

            HandleResponse(Jspg2Client.ReadPrev(txtSkip.Text));

        }

        private void btnLast_Click(object sender, EventArgs e)

        {

            HandleResponse(Jspg2Client.ReadLast());

        }

        private void btnFirst_Click(object sender, EventArgs e)

        {

            HandleResponse(Jspg2Client.ReadFirst());

        }

Update, Delete, and Add

In the same way we discover that Update, Add, and Delete require a single argument, EMPNO, which is Employee’s primary key, so except for the method name we write mostly the same code for each.  Here is the Update logic: -

        private void btnUpdate_Click(object sender, EventArgs e)

        {

            HandleResponse(Jspg2Client.Update(txtEmpno.Text));

        }

Update must follow an enquiry, either a single-record enquiry using the primary key (EMPNO) and the [Enquiry] button, or a scrolling enquiry with ReadNext or ReadPrev.  The enquiry will have returned a checksum which is used to prevent invalid updates.  If, between your enquiry and update another user changes the record then a different checksum will be calculated: this difference will be detected within the interface, and your update rejected: -

To update a record we’ll enter new data in various textboxes, then click the [Update] button.  Here I’ve removed MIDINIT by entering “null” (must be lower case), set JOB to “Manager”, and DEPTMGR to T (for True). 

Click [Update] and the record is updated, and new values displayed: -

Delete is identical except that it invokes Jspg2Client.Delete.   Like Update, it must follow an enquiry: -

        private void btnDelete_Click(object sender, EventArgs e)

        {

            HandleResponse(Jspg2Client.Delete(txtEmpno.Text));

        }

Add requires some extra logic.  If it were the same as Update then it would be misleading: Update only sends the changed data to the service except for the record key (EMPNO).  With the Add method you want all the data that you see displayed in the form’s controls to be included in the new record, whether you’ve edited it or whether it has come from a preceding read.  Before the Add the btnAdd_Click event therefore sets the Jspg2Client property corresponding to each of the textboxes except the primary key (EMPNO) and Skip.   Unlike HandleValidResponse/SetFormValues these assignments are NOT surrounded by EditMode = false; and EditMode = true; because the point of these assignments is to set the relevant Changed flag.

        private void btnAdd_Click(object sender, EventArgs e)

        {

            // Validate all textboxes (except 1ry Key and Skip), ensuring that they will be included in following Add because Changed will have been set

            Jspg2Client.WORKDEPT = txtWorkdept.Text;

            Jspg2Client.FIRSTNME = txtFirstNme.Text;

            Jspg2Client.MIDINIT = txtMidInit.Text;

            Jspg2Client.LASTNAME = txtLastName.Text;

            Jspg2Client.PHONENO = txtPhoneNo.Text;

            Jspg2Client.HIREDATE = txtHireDate.Text;

            Jspg2Client.JOB = txtJob.Text;

            Jspg2Client.EDLEVEL = txtEdlevel.Text;

            Jspg2Client.SEX = txtSex.Text;

            Jspg2Client.BIRTHDATE = txtBirthDate.Text;

            Jspg2Client.SALARY = txtSalary.Text;

            Jspg2Client.BONUS = txtBonus.Text;

            Jspg2Client.COMM = txtComm.Text;

            Jspg2Client.CURRENCY = txtCurrency.Text;

 

            // Now add the new record

            HandleResponse(Jspg2Client.Add(""));

        }

Clear and Close

These are basic methods that do not involve the web service. 

 

Clear simply sets all the textboxes to blank.  This must be done with EditMode = false; to prevent error messages from blank required fields

        private void btnClear_Click(object sender, EventArgs e)

        {

            EditMode = false;

            lblError.Text = "";

            lblBrowseCount.Text = "";

            lblReturnCode.Text = "";

            txtEmpno.Text = "";

            txtWorkdept.Text = "";

            txtSkip.Text = "0";

            txtFirstNme.Text = "";

            txtMidInit.Text = "";

            txtLastName.Text = "";

            txtPhoneNo.Text = "";

            txtHireDate.Text = "";

            txtJob.Text = "";

            txtEdlevel.Text = "";

            txtSex.Text = "";

            txtBirthDate.Text = "";

            txtSalary.Text = "";

            txtBonus.Text = "";

            txtComm.Text = "";

            txtCurrency.Text = "";

            EditMode = true;

        }

Close is

        private void btnClose_Click(object sender, EventArgs e)

        {

            this.Close();

        }

Client Projects with Multiple Forms

In Using a Client Interface project MyJSvTests was created with a single form, JSPG2Test. Starting this project with Visual Studio automatically opens form JSPG2Test.   Now you want to test another interface?   You could of course create another project, but if your new client is another C# form then you may prefer to add this form to MyJScTests.

When you create a C# forms project, one of the objects created in it is Program.cs, containing this code: -

using System;

using System.Collections.Generic;

using System.Linq;

using System.Threading.Tasks;

using System.Windows.Forms;

 

namespace MyJSvClientTests

{

    static class Program

    {

        /// <summary>

        ///  The main entry point for the application.

        /// </summary>

        [STAThread]

        static void Main()

        {

            Application.SetHighDpiMode(HighDpiMode.SystemAware);

            Application.EnableVisualStyles();

            Application.SetCompatibleTextRenderingDefault(false);

            Application.Run(new JSPG2Test());

        }

    }

}

My next task was to test JSPG2A, a version of JSPG2 that returns several Employee records.  If I add
           
Application.Run(new JSPG2ATest());
to this, then the project will first open JSPG2test, then when I close this it will open JSPG2ATest.   This worked well when I was testing for differences in behaviour between JSPG2 and JSPG2A.   When I was working with just one of the programs I’d comment out the Application.Run that I didn’t want.  I didn’t bother creating a menu.  

Sample Clients

It is planned that when you generate an interface you can check one or more of the Client options: -

This will generate a sample client with code like that described above, in the option(s) that you choose.  Initial validation of this will be with a C# Windows Form, then C# Web Program, then Visual Basic, then Java.  Further sample client options will be provided if required.

These sample clients are intended to provide initial code for users to start with, but we expect that they will need significant editing to meet actual requirements.  As well as dealing with the web service, the client program may access local data, interact with other web services, and be part of a larger conversation involving authentication and data passing from step to step. 

Appendices

Programs used as Examples

Program

Function

Comment

JSPG1

DB2 Enquiry

Generated web service, JSON, Uses Database Sample, Table Employee, max = 6.

JSPG1V

VSAM Enquiry

Like JSPG1, but uses VSAM file Custf

JSPG2

DB2 Update

Generated like JSPG1 except Update, max = 1

JSPG2A

DB2 Update

Like JSPG2 except max = 6

Returning Multiple Records

Programs JSPG2 and JSPG2A have been generated to perform the same task, but JSPG2 was defined with Max=1 and JSPG2A with Max=6.  The process of defining the interface JSPG2AClient and the test form JSPG2ATest is exactly as described above for JSPG2, and both tests behaved identically except for scrolling: for JSPG2A, ReadNext ([>] button) was instant (< 1 millisecond) except for every 6th record when a Request/Response was required.  Each Request/Response took approximately 3 seconds with my test environment, and I couldn’t find any statistically-significant difference between request/responses from JSPG2 and JSPG2A even though JSPG2A’s messages were larger.  While returning large output messages than necessary seems wasteful, there is also hidden waste like having to read-and-skip unwanted records to get to the one that you want, so my conclusion is that you should set Max to as large a value as you might conceivably need. 

My use of Max=6 is NOT a balance between excessively large messages and other overheads. 6 was chosen because my priority was developing code that would silently handle the situation where Max was not large enough to get all the records.  For a production situation with data like mine I’d have set Max=14.

Logic used when Max > 1

When Max > 1 then the interface saves the first n records in a list. Thus the first WorkDept=D11 Enquiry saved the first 6 records.  On reading the 7th record the next 6 records are added to this list, and so on until the last record (known from BrowseCount) is read.   Backward scrolling – [<] and [<<] – is always instant, while forward scrolling – [>] – is instant except for every 6th record.  Scroll to end – [>>] – might require several request/responses.

The client’s record list is maintained until there is another [Enquiry].  If a record is updated then the updated record replaces the original record in the list.  Added records are added to the list and BrowseCount incremented.  Deleted records are deleted from the list and Browsecount reduced, but the deleted record remains displayed until the next scrolling command or [Enquiry].

In the following appendices you’ll see significant differences in JSPG2Client/JSPG2AClient logic, but none in JSPG2Test/JSPG2ATest.

Measuring Response Time

I measured response times by adding code like this to the interface.  If relevant, you should do the same to check out your situation: -

JSPG2Client and JSPG2AClient.Scroll.  Logic in … and the last statement are different.

        private bool Scroll(int Increment, string PSkip = null,string PWORKDEPT = null)

        {

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();

            stopwatch.Stop();

            Debug.Print("Scroll Stopwatch: ms=" + stopwatch.ElapsedMilliseconds.ToString());

            return DoRead(PSkip, "", PWORKDEPT);

        }

JSPG2Client and JSPG2AClient.DoRead.  It was necessary to change the generated statement
           
return = RequestResponse();

to         bool Result = RequestResponse();

so that the Stop time could be reported.

        public bool DoRead(string PSkip = null,string PEMPNO = null,string PWORKDEPT = null)

        {

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();

            bool Result = RequestResponse();

            stopwatch.Stop();

            Debug.Print("RequestResponse Stopwatch: ms=" + stopwatch.ElapsedMilliseconds.ToString());

            return Result;

        }

Browsecount

Browsecount is calculated differently for SQL and for VSAM.   For SQL it is always accurate, because the SQL logic starts with SELECT COUNT(*), e.g.

005440         SELECT COUNT(*) INTO :OJSPG1.JZ-Employee-BrowseCount FROMJSPG1

005450              EMPLOYEE WHERE WORKDEPT LIKE :JZLIKE                JSPG1

There is no equivalent of COUNT(*) with VSAM.  Since the point of BrowseCount is to control scrolling, and for this purpose it is sufficient if it is greater than the number read unless all the browsed records have been read, the value of BrowseCount for VSAM is : -
            If the browse list has been read to the end, the BrowseCount is accurate.
            If the browse list has not been read completely, the BrowseCount is 1 greater than the number of records that have been read.

Example:  Program JSPG1V is like program JSPG1, but instead of reading data from DB2 table EMPLOYEE it reads a VSAM file CustF.  JSPG1V was generated with Max=6, so: -

Enter Name = Barnes and click [Read].  The first 6 records are read, and BrowseCount = 7: -

Scrolling forward [>] is instant until the 7th record is reached when the next 6 records are read, and BrowseCount becomes 13.

Last record, [>>], read another 6 records, and so might need to be clicked several times to really get to the end.  With my test data this browse returns 23 records, so three [>>] clicks are needed to get to the end.

This logic was designed for VSAM to avoid the need to read all the VSAM records with every browse enquiry just to calculate BrowseCount accurately.

Jazz Message Definitions

This is the message definition for program JSPG2.  Note that it contains three main parts, but also refers to other definitions through COPY statements.  To deduce the full data rules, you need to follow the Assign relationships, for example to understand that IJSPG2.EMPNO must be numeric in the range 1-999999 you need to look up EMPLOYEE.EMPNO.   This definition gives Jazz all the information that it needs to create the interface. 

*# Last Updated by JAZZUSR at 6/12/2020 1:01:08 PM

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

COPY Employee;

COPY TYPES;

DEFINE MyJSv-JSPG2 SYSTEM DATA([Not in COBOL

    INPUT VARCHAR(6) VALUE 'IJSPG2',

    OUTPUT VARCHAR(6) VALUE 'OJSPG2',

    MType CHAR(4) VALUE 'JSON',

    Template CHAR(8) VALUE '@JSF1Upd',

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

DEFINE IJSPG2 SERVICE INPUT DATA(

    Function CHAR(1) CAPS CODES(E:Enquiry,U:Update,A:Add,D:Delete)  VALUE Enquiry,

    JZ-Employee-Skip SMALLINT VALUE 0 RANGE(0:999),

    JZ-Employee GROUP,

        EMPNO CHAR(6) ASSIGN EMPLOYEE.EMPNO,

        FIRSTNME CHAR(12) ASSIGN EMPLOYEE.FIRSTNME,

        MIDINIT CHAR(1) ASSIGN EMPLOYEE.MIDINIT,

        LASTNAME CHAR(15) ASSIGN EMPLOYEE.LASTNAME,

        WORKDEPT CHAR(3) ASSIGN EMPLOYEE.WORKDEPT,

        PHONENO CHAR(4) ASSIGN EMPLOYEE.PHONENO,

        HIREDATE CHAR(9) ASSIGN EMPLOYEE.HIREDATE,

        JOB CHAR(8) ASSIGN EMPLOYEE.JOB,

        EDLEVEL CHAR(7) ASSIGN EMPLOYEE.EDLEVEL,

        SEX CHAR(1) ASSIGN EMPLOYEE.SEX,

        BIRTHDATE CHAR(9) ASSIGN EMPLOYEE.BIRTHDATE,

        SALARY CHAR(15) ASSIGN EMPLOYEE.SALARY,

        BONUS CHAR(15) ASSIGN EMPLOYEE.BONUS,

        COMM CHAR(15) ASSIGN EMPLOYEE.COMM,

        CURRENCY CHAR(3) ASSIGN EMPLOYEE.CURRENCY,

        DEPTMGR CHAR(5) ASSIGN EMPLOYEE.DEPTMGR,

        Checksum CHAR(40),

        END GROUP);

DEFINE OJSPG2 SERVICE OUTPUT DATA(

    Error VARCHAR(80),

    JZ-Employee-ReadTo SMALLINT VALUE 0,

    JZ-Employee-NbrReturned SMALLINT VALUE 0,

    JZ-Employee-BrowseCount SMALLINT VALUE 0,

    JZ-Employee (1) GROUP,

        JZ-Employee-ReturnCode LIKE Types.ReturnCode,

        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,

        DEPTMGR LIKE EMPLOYEE.DEPTMGR ASSIGN EMPLOYEE.DEPTMGR,

        Checksum CHAR(40),

        END GROUP);

Note that the output record is defined with a dimension, even though it has extent = 1.  This value corresponds to the Max value given for Employee when the service was generated. For JSPG2A this would be 6.

 

Here is the definition of the EMPLOYEE record, referenced in LIKE and ASSIGN properties: -

*# Last Updated by JAZZUSR at 31/08/2020 1:33:28 PM

*# Created from Table:EMPLOYEE, Schema:ROBERTBW10, Database:Sample by JazzUser at 26/03/2019 4:25:46 PM

COPY Department;

DEFINE EMPLOYEE SQL DATA(   

    EMPNO CHAR(6) PIC '999999' REQUIRED KEY,

    FIRSTNME VARCHAR(12) REQUIRED,

    MIDINIT CHAR (1),

    LASTNAME VARCHAR(15) REQUIRED,

    WORKDEPT CHAR(3) CAPS DKEY 'XEMP2' EXISTS DEPARTMENT.DEPTNO,

    PHONENO CHAR(4) PIC '9999',

    HIREDATE DATE,

    JOB CHAR(8),

    EDLEVEL SMALLINT REQUIRED,

    SEX CHAR(1) CAPS CODES(M:Male, F:Female),

    BIRTHDATE DATE,

    SALARY MONEY(9,2) MIN 0,

    BONUS MONEY(9,2) MIN 0,

    COMM MONEY(9,2) MIN 0,

    CURRENCY CHAR(3),

    DEPTMGR BOOLEAN);

Messages – COBOL, JSON, C#, and Binding

We wrote a web service program in MANASYS Jazz, and when we clicked [Process] this was turned into COBOL.  The COBOL program will contain data definitions based on the Jazz-format definitions above.  For example, this is the request message, IJSPG2: -

003360 01  IJSPG2.                                                      JSPG2

003370      03 JZ-Function PIC X VALUE 'E'.                             JSPG2

003380      03 JZ-Employee-Skip PIC S9(4) COMP-5 VALUE 0.               JSPG2

003390      03 JZ-Employee.                                             JSPG2

003400        05 EMPNO PIC X(6) VALUE SPACES.                           JSPG2

003410        05 FIRSTNME PIC X(12) VALUE SPACES.                       JSPG2

003420        05 MIDINIT PIC X VALUE SPACES.                            JSPG2

003430        05 LASTNAME PIC X(15) VALUE SPACES.                       JSPG2

003440        05 WORKDEPT PIC XXX VALUE SPACES.                         JSPG2

003450        05 PHONENO PIC XXXX VALUE SPACES.                         JSPG2

003460        05 HIREDATE PIC X(9) VALUE SPACES.                        JSPG2

003470        05 JOB PIC X(8) VALUE SPACES.                             JSPG2

003480        05 EDLEVEL PIC X(7) VALUE SPACES.                         JSPG2

003490        05 SEX PIC X VALUE SPACES.                                JSPG2

003500        05 BIRTHDATE PIC X(9) VALUE SPACES.                       JSPG2

003510        05 SALARY PIC X(15) VALUE SPACES.                         JSPG2

003520        05 BONUS PIC X(15) VALUE SPACES.                          JSPG2

003530        05 COMM PIC X(15) VALUE SPACES.                           JSPG2

003540        05 JZ-CURRENCY PIC XXX VALUE SPACES.                      JSPG2

003550        05 DEPTMGR PIC XXXXX VALUE SPACES.                        JSPG2

003560        05 Checksum PIC X(40) VALUE SPACES.                       JSPG2

To get the request message the COBOL program contains

005700     EXEC CICS                                                    JSPG2

005710         GET CONTAINER(JZInputContainer) INTO(IJSPG2)             JSPG2

005720             RESP(JZ-RESPONSE)                                    JSPG2

005730     END-EXEC.                                                    JSPG2

Similarly, there will be a COBOL definition of the response, which will be sent back to the client with

021250     EXEC CICS                                                    JSPG2

021260         PUT CONTAINER(JZContainerName) FROM(OJSPG2)              JSPG2

021270             RESP(JZ-RESPONSE)                                    JSPG2

021280     END-EXEC.                                                    JSPG2

But the client is not COBOL!  The messages must be converted to a standard form that can be understood, whatever the language the client uses.  For this to happen, after program JSPG2 was compiled a “binding object” is produced to convert the messages between COBOL-format and JSON, the most popular standard form, and JSON descriptions of the request and response messages were produced.

With Jazz configured for z/OS, this all happens on the mainframe as a result of JCL steps that are automatically inserted into the job that compiles the COBOL.  With Jazz configured to work with Micro Focus Enterprise Developer, this is done through the dialog described here.

Request message as JSON.

This is the JSON generated from the COBOL for the request message

{

  "$schema" : "http:\/\/json-schema.org\/draft-04\/schema#",

  "title" : "JSPG2",

  "description" : "Micro Focus Enterprise Developer - This generated JSON schema document is provided 'as is' and without any warranties of any kind, and may be used by licensee solely for the purposes of describing a REST API. Micro Focus shall not be responsible for and hereby disclaims any liabilities that may result from licensee's use of or modifications to this generated JSON schema document.",

  "type" : "object",

  "properties" :

  {

    "JSPG2" :

    {

      "type" : "object",

      "properties" :

      {

        "IJSPG2" :

        {

          "type" : "object",

          "properties" :

          {

            "JZ_Function" :

            {

              "type" : "string",

              "maxLength" : 1

            },

            "JZ_Employee_Skip" :

            {

              "type" : "integer"

            },

            "JZ_Employee" :

            {

              "type" : "object",

              "properties" :

              {

                "EMPNO" :

                {

                  "type" : "string",

                  "maxLength" : 6

                },

                "FIRSTNME" :

                {

                  "type" : "string",

                  "maxLength" : 12

                },

                "MIDINIT" :

                {

                  "type" : "string",

                  "maxLength" : 1

                },

                "LASTNAME" :

                {

                  "type" : "string",

                  "maxLength" : 15

                },

                "WORKDEPT" :

                {

                  "type" : "string",

                  "maxLength" : 3

                },

                "PHONENO" :

                {

                  "type" : "string",

                  "maxLength" : 4

                },

                "HIREDATE" :

                {

                  "type" : "string",

                  "maxLength" : 9

                },

                "JOB" :

                {

                  "type" : "string",

                  "maxLength" : 8

                },

                "EDLEVEL" :

                {

                  "type" : "string",

                  "maxLength" : 7

                },

                "SEX" :

                {

                  "type" : "string",

                  "maxLength" : 1

                },

                "BIRTHDATE" :

                {

                  "type" : "string",

                  "maxLength" : 9

                },

                "SALARY" :

                {

                  "type" : "string",

                  "maxLength" : 15

                },

                "BONUS" :

                {

                  "type" : "string",

                  "maxLength" : 15

                },

                "COMM" :

                {

                  "type" : "string",

                  "maxLength" : 15

                },

                "JZ_CURRENCY" :

                {

                  "type" : "string",

                  "maxLength" : 3

                },

                "DEPTMGR" :

                {

                  "type" : "string",

                  "maxLength" : 5

                },

                "Checksum" :

                {

                  "type" : "string",

                  "maxLength" : 40

                }

              }

            }

          }

        }

      }

    }

  }

}

RequestJSPG2.cs

Just as we use COBOL definitions within the web server program JSPG2, within the C# program JSPG2Client we convert the JSON into a hierarchy of C# classes.  Here is the request definition, as it will be used within JSPG2Client.  Except for naming, there is no difference between this and RequestJSPG2A.cs

namespace MyJSv

{

    public class RequestJSPG2

    {

        public class JSPG2_

        {

            public class IJSPG2_

            {

                public string JZ_Function { get; set; }

                public int JZ_Employee_Skip { get; set; }

                public class JZ_Employee_

                {

                    public string EMPNO { get; set; }

                    public string FIRSTNME { get; set; }

                    public string MIDINIT { get; set; }

                    public string LASTNAME { get; set; }

                    public string WORKDEPT { get; set; }

                    public string PHONENO { get; set; }

                    public string HIREDATE { get; set; }

                    public string JOB { get; set; }

                    public string EDLEVEL { get; set; }

                    public string SEX { get; set; }

                    public string BIRTHDATE { get; set; }

                    public string SALARY { get; set; }

                    public string BONUS { get; set; }

                    public string COMM { get; set; }

                    public string JZ_CURRENCY { get; set; }

                    public string Checksum { get; set; }

                }

                public JZ_Employee_ JZ_Employee { get; } = new JZ_Employee_();

            }

            public IJSPG2_ IJSPG2 { get; } = new IJSPG2_();

        }

        public JSPG2_ JSPG2 { get; } = new JSPG2_();

    }

}

Note the way in which the lower-level classes are made addressable by naming the original class with a _, e.g. JSPG2_ and then following this class with

       public JSPG2_ JSPG2 { get; } = new JSPG2_();

From public class IJSPG2_ this corresponds directly to the JSON schema.  The outer two layers are added to ensure that the structure confirms to the JSON that is received, otherwise the JSON would needs to be text-edited on input and output before being serialised/de-serialised.   Statements can now be generated into JSPG2Client reflecting this structure, for example
           
Request.JSPG2.IJSPG2.JZ_Employee.EMPNO = _EMPNO;

ResponseJSPG2.cs

Like RequestJSPG2.CS, this maps the hierarchical structure of the response, and has a couple of levels at the top to reflect the JSON structure: -

namespace MyJSv

{

    public class ResponseJSPG2

    {

        public class JSPG2Response_

        {

            public class OJSPG2_

            {

                public class JZ_Error_

                {

                    public int JZL_Error { get; set; }

                    public string JZD_Error { get; set; }

                }

                public JZ_Error_ JZ_Error { get; } = new JZ_Error_();

                public int JZ_Employee_ReadTo { get; set; }

                public int JZ_Employee_NbrReturned { get; set; }

                public int JZ_Employee_BrowseCount { get; set; }

                public class JZ_Employee_

                {

                    public string JZ_Employee_ReturnCode { get; set; }

                    public string EMPNO { get; set; }

                    public class FIRSTNME_

                    {

                        public int JZL_FIRSTNME { get; set; }

                        public string JZD_FIRSTNME { get; set; }

                    }

                    public FIRSTNME_ FIRSTNME { get; } = new FIRSTNME_();

                    public string MIDINIT { get; set; }

                    public class LASTNAME_

                    {

                        public int JZL_LASTNAME { get; set; }

                        public string JZD_LASTNAME { get; set; }

                    }

                    public LASTNAME_ LASTNAME { get; } = new LASTNAME_();

                    public string WORKDEPT { get; set; }

                    public string PHONENO { get; set; }

                    public int HIREDATE { get; set; }

                    public string JOB { get; set; }

                    public int EDLEVEL { get; set; }

                    public string SEX { get; set; }

                    public int BIRTHDATE { get; set; }

                    public float SALARY { get; set; }

                    public float BONUS { get; set; }

                    public float COMM { get; set; }

                    public string JZ_CURRENCY { get; set; }

                    public string DEPTMGR { get; set; }

                    public string Checksum { get; set; }

                }

                public JZ_Employee_ JZ_Employee { get; } = new JZ_Employee_();

            }

            public OJSPG2_ OJSPG2 { get; } = new OJSPG2_();

        }

        public JSPG2Response_ JSPG2Response { get; } = new JSPG2Response_();

    }

}

Response JSPG2A

Unlike Request, there is a significant difference for JSPG2A.  There is nothing in the JSPG2 structure allowing JZ_Employee to repeat, and references like this in JSPG2Client don’t have a subscript.
           
_EMPNO = Response.JSPG2Response.OJSPG2.JZ_Employee.EMPNO;

The equivalent in JSPG2AClient is generated as
       _EMPNO = Response.JSPG2AResponse.OJSPG2A.JZ_Employee[IXT1Sub].EMPNO;

To support this the definition of JZ_Employee is generated as
           
public List<JZ_Employee_>JZ_Employee { get; set;} = new List<JZ_Employee_>();

Understanding the Client Interface

We started with a web service, written in MANASYS Jazz and converted to COBOL and JSON objects which were compiled on a “Mainframe”, represented in the right section of this diagram repeated from above.  Clicking [Client] and then [Create Interface] created the middle section, the interface.

The interface is generated as C#, using .NET Core, and so should run in a wide variety of environments: Windows, UNIX, Linux, IOS, Android, … The actual client apps may be written in Java, C#, VB, or other technologies.   This section explains the structure and function of the interface, which is based on Template @JazzClient.cs.   You can see examples of generated interfaces at https://www.jazzsoftware.co.nz/Docs/JSPG2Client.cs.txt and https://www.jazzsoftware.co.nz/Docs/JSPG2AClient.cs.txt.

It contains a number of sections

1.    Private

//  Private - objects that are not known outside the Client object

Here you find things that are NOT communicated to the Client Program. 

·         The actual Request and Response messages,
    private RequestJSPG2 Request = new RequestJSPG2();   // Actual request message
    private ResponseJSPG2 Response = new ResponseJSPG2(); // Actual response message

·         Changed.  A struct, SetByUser, contains a list of all the properties that can be set by the client.  It is instantiated with
   private SetByUser Changed = new SetByUser();
The interface keeps track of which fields have been changed since a response, so that an Update can send only changed fields.

·         Private fields like Function and Checksum which are managed within the interface.

2.    Key Properties

         // Key Properties - fields used by methods to access records

Here you find properties that are used by methods to specify which records are to be handled, in this case EMPNO, WORKDEPT, and Skip.  

·         Program JSPG2 updates the Employee table, which has been defined with primary key EMPNO

·         WORKDEPT is a duplicate key

·         Because WORKDEPT may specify several Employee records, Skip also appears here to control scrolling.

Property EMPNO shows the typical structure of a property.  There is a private variable _xxx, e.g. “_EMPNO” that the client can’t see, and a public property “EMPNO” that it can.  The value of the private variable is available with get, and its value is set through code like that below

        private string _EMPNO = null;

        public string EMPNO // => Request.EMPNO

        {

            get => _EMPNO;

            set

            {

                Changed.EMPNO = true;

                _EMPNO = null;

                if (value == "")

                {

                    _ERROR = "Value required";

                    _JZ_Employee_ReturnCode = "E";

                    return;

                }

                _EMPNO = IsInt(value, 0, 999999, "EMPNO");

                Request.JSPG2.IJSPG2.JZ_Employee.EMPNO = _EMPNO;

            }

        }

The set code starts by setting the appropriate Changed flag, and then checks that the value entered is valid.  For required fields like EMPNO validation starts by checking that a value has been given. See PHONENO below to see how optional fields are handled. This is followed by validation that depends on the field’s definition – EMPNO must be an integer, in the range 0 to 999999.   Finally, the value is assigned to the request message.

3.    I/O Data

        //  I/O Data - non-key fields, will be set in Add, Update requests

Like Key fields, these communicate with the Client through get and set methods like that for EMPNO.  PHONENO is an example of an optional field: unlike EMPNO which was required, a PHONENO value can be absent, or “null”.   For SQL optional fields “null” (lower case) will cause the database field to be set to null, and cannot be assigned as the value of a string field.

        private string _PHONENO = null;

        public string PHONENO // => Request.PHONENO

        {

            get => _PHONENO;

            set

            {

                Changed.PHONENO = true;

                _PHONENO = null;

                if (value == "" || value == "n" || value == "nu" || value == "nul")

                    return;

                if (value == "null")

                    _PHONENO = "null";

                else

                    _PHONENO = IsInt(value, 0, 9999, "PHONENO");

                Request.JSPG2.IJSPG2.JZ_Employee.PHONENO = _PHONENO;

            }

        }

4.    Output

From the Jazz Message Definitions you can see that there are several fields like ERROR in the output message that have no equivalent in the input message. These provide only a get method, so the Client can’t change them.

        private string _ERROR = null;

        public string _ERROR // Readonly

        {

            get => _ERROR;

        }

If displayed label controls will be used.

5.    Value properties

Within the properties you’ll see a few output properties named xxxx_Value immediately following the xxxx property. _Value properties exist when

1.    A property relates to a field defined to MANASYS with CODES.

2.    A property relates to a field that has a meaning defined by the system.

Example 1.  The SEX property is followed by

        public string SEX_Value // => Request.SEX_Value

        {

            get

            {

                if (_SEX == "M")

                    return "Male";

                if (_SEX == "F")

                    return "Female";

                return "";

            }

        }

This is because SEX is defined with CODES: -
           
SEX CHAR(1) CAPS CODES(M:Male, F:Female),

Example 2.  The output field JZ_Employee_ReturnCode is followed by JZ_Employee_ReturnCode_Value.  There is also an example, StatusCode_Value in the Standard Response Properties, which returns HttpCode as a string, “OK” instead of 200.

3.    Functions

This section contains the routines required by set , such as IsInt which is used to check that an input value is an integer, InList to check that a value is in a list (like SEX), and so on.   IsInt is typical, it starts by initializing ERROR and return code properties, then it checks Value to see if it is valid.  If not, the ERROR will be set to an appropriate message and the return code set to “E”.

        private string IsInt(string Value, int MinVal, int maxval, string FieldName)

        {

            _ERROR = "";

            _JZ_Employee_ReturnCode = "";

            if (Value == "") return "0";

            int IX = 0;

            if (!int.TryParse(Value, out IX))

            {

                _ERROR = FieldName + " Value is Not Numeric";

                _JZ_Employee_ReturnCode = "E";

            }

            else if (IX < MinVal || IX > maxval)

            {

                _ERROR = FieldName + " Value out of range";

                _JZ_Employee_ReturnCode = "E";

            }

            return Value;

        }

4.    Standard Response Properties

All html messages have some information in their headers, and so the interface provides several output-only properties returning this: -

        public int StatusCode            // returns HttpStatusCode as a number

        public string StatusCode_Value  // returns HttpStatusCode as a string, e.g. 200 => “OK”

        public string IsSuccessStatusCode// True if the request is successful

        public string ReasonPhrase       // returns the reason for failure (or not). 

        public string RawResponse        // blank except when unsuccessful request

5.    RequestResponse

A standard method that is used by all methods except [Clear] and [Close].  The request message is converted to JSON and sent, the response received and converted back, and then the response values are assigned to the output properties.

6.    Methods

a.    JSPG2Client

Because JSPG2 is controlled by Function, which is defined

    Function CHAR(1) CAPS CODES(E:Enquiry,U:Update,A:Add,D:Delete) VALUE Enquiry,

there will be Enquiry, Update, Add, and Delete methods. 

Because scrolling is possible, logic will be based on the @ReadScroll.cs template, and so scrolling methods ReadNext, ReadLast, ReadPrev, and ReadFirst will be generated into JSPG2Client. 

Methods get their input values from parameters, not properties, allowing them to check that the values that they are given are valid (for example, for an Update EMPNO hasn’t changed).  Typically they check their arguments and then invoke RequestResponse, either directly or through another method (e.g. Scroll and DoRead).

Update will put changed values into the request, but ignore any that haven’t been changed.   JSPG2Client will have saved CHECKSUM from the previous Enquiry, this is returned in the request and will be checked by the service, and the update rejected if it differs from the recalculated value.

So will Add, but JSPG2Test ensures that all textboxes except the primary key (EMPNO) and Skip are marked as changed.  A blank EMPNO is passed in the message, so the service will find the next free key.  Browsecount will be incremented.

Delete only needs the primary key to delete a record, and like Update will return the Enquiry’s Checksum to be checked.
           
Result = RequestResponse(false);
is used so that the deleted record remains displayed in the response.  Browsecount will be reduced.

For detail, see https://www.jazzsoftware.co.nz/Docs/JSPG2Client.cs.txt

b.    JSPG2AClient

JSPG2AClient differs from JSPG2Client in only one way:  it returns several EMPLOYEE records at a time. This has had minor effects on the Jazz and C# data definitions, but it has a major effect on the code generated for JSPG2AClient, particularly the Enquiry, Update, Add, and Delete methods.  

For an enquiry by WorkDept 6 records are read and the first returned to the client (JSPG2ATest), but all 6 are saved in a list.  Assignment statements need to specify a subscript, initially 0, to assign data from the first record to the properties returned to the client.   Scrolling within the 6 records is very quick, because it’s just a subscript change and doesn’t require a request/response.

If scrolling goes beyond the first 6, the next 6 are read and added to the list.

The list is updated to reflect Update, Delete, and Add, so that it reflects the new database.  For Delete and Add Browsecount will change.

For detail, see https://www.jazzsoftware.co.nz/Docs/JSPG2AClient.cs.txt.

7.    Routines

The last section of the interface contains the routines that are used by methods. 

ResetChanged resets all the SetByUser flags, marking all input/output fields as unchanged. 

AssignResponseToProperties assigns data from the response message to the interface properties, whether private (like CheckSum), Output (like Error), or Input/Output.

ClearRequest sets all request fields to null, preventing data carry-over

AddPrivateFieldsToRequest adds the fields to the request that are not shared with the client.  Currently this is only CheckSum.

Road Map

MANASYS Jazz Version 3.16.1.230 was the first build to incorporate client interface generation, although only as a proof-of-concept.  The feature was tested with a web service updating a single DB2 table: program JSPG2 updates table EMPLOYEE, from IBM’s Sample DB2 database.  I added two extra fields, Currency to prove that column names that are COBOL reserved words can be handled, and DeptMgr to prove that Boolean fields can be handled across the COBOL and Client app worlds.

Build 16.2.239 added: -

·         Enquiry-only web services.

·         Web services that return multiple records – e.g. several EMPLOYEE records – in a message.  Timing experiments showed that there was no measurable time difference in returning a single-record or multi-record web service, and scrolling through a list of records was instant compared to ~3 seconds per record for each request/response.

·         Add and Delete methods as well as Read and Update.  Add and Delete functions are optional.

·         Update methods may have Max > 1, for update as well as enquiry only

·         VSAM records as well as DB2.

Build 16.2.240 added: -

·         Related Fields.  When a web service is generated from a definition including fields using EXISTS, like
WORKDEPT CHAR(3) CAPS DKEY 'XEMP2' EXISTS DEPARTMENT.DEPTNO,
the generation dialog offers the option of selecting fields from DEPARTMENT.  If (e.g.) DEPARTMENT.DEPTNO is selected then this is included in the output message as an output-only field.

Not handled yet: Parent/child record sets, VSAM records containing repeating fields, repeating groups, or redefinitions.

We are looking for early adopters to join us on this exciting journey: not only will they get some immediate benefits from the features that MANASYS Jazz already offers, they will be very influential in setting our development priorities.

Planned development (in no particular order): -

·         Check that all the data types in IBM’s Sample Database that are supported by Jazz* can be handled
*     Jazz doesn’t support BLOB, CLOB, and National data.

·         Support VSAM groups and arrays (dimensions), and redefinition

·         Handle browsing by multiple fields: Compound key, also two or more alternate indexes.

·         Support Max=*, where the number is unknown until run time. 

·         Support multiple-record services (Parent/Child, and more complex record relationships)

·         Support conversational web services.  An implementation working like ASP.NET “Viewstate” has been defined that would allow data to be handed from one Request/response to the next.  Like ASP’s Viewstate the data will be encrypted so that even if seen by the client it won’t be able to be understood or changed. 

·         Generate prototype Clients.  The design and this document anticipates that MANASYS will generate a client in C#, VB, or Java, for Windows or a Web page.  It is not expected that this client will be any more than an initial prototype, like the sample JSPG2Test Windows Form.  It will provide useful code snippets that can be used in the client that the user actually develops, but it is not currently possible for MANASYS Jazz to know what the user actually wants. For example, the client may need to access other web services, local databases, or API’s like GPS location data. 

·         Allow local validation logic to be defined, for example checking that a credit card number has the correct format including check digit, allowing users to duplicate the function of CHECKR properties in the service.