CALL and INVOKE

CALL and INVOKE both pass control [and parameters] to another, separately compiled object, so they are described together because it’s useful to be able to compare them.  However they are not the same: - 

·         CALL passes control to a subprogram which is written separately but linked into the same executable program as the object containing the CALL. CALL may be used in either Batch or CICS programs.   Control will return to the statement following CALL unless there’s a program error (Abnormal termination, or “Abend”).

·         INVOKE is only valid in CICS programs, and the “call” is managed by CICS.  The invoked object may be another CICS program, including another CICS program within another CICS system, or it may be a web service.  Program execution may be terminated after INVOKE has passed control.

The CALL Statement

FUNCTION

To pass control and parameters to a subprogram. Control is expected to return to the calling program when the subprogram finishes.

FORMAT

            CALL Name [(parameter [,parameter]...)] ;

For example:

      CALL CHKORDER (ORDER.*); 

 

Subprograms are written separately. This creates some error possibilities: -

·         The order and type of the parameters in the CALL statement must match exactly the corresponding parameters in the subprogram. For example, suppose that you had a routine that converted a CHAR(20) string into a DECIMAL(17) number according to particular rules.  You might write: -

      CALL StrNbr (CHARField, DECField);
But what if CHARField were not defined as CHAR(20)?  Or DECField were BINARY or FLOAT or some other numeric format?  Or you wrote

      CALL StrNbr(DECField, CHARField);

mistakenly writing the parameters in the wrong order?

·         The subprogram and calling program must be compatible.  A subprogram can’t used in both Batch and CICS environments unless it avoids statements that are only valid in one environment, or are handled differently. This means that a dual-use subprogram can’t use any I/O statement (PROCESS, GET, DELETE, PRINT) or CICS-Specific statements (SEND, INVOKE).

 

To prevent these errors Jazz requires a DEFINE statement to define the interface.  Somewhere in your program before the CALL statement you will write a statement like this

DEFINE StrNbr PARAMETERS BOTH DATA(

            CHARField CHAR(20) INPUT,

            Number DECIMAL(17) OUTPUT);

Now with the statement

CALL StrNbr (w.CF, w.Nbr);

Jazz can check that w.CF is either a CHAR(20) field, or some format that can be assigned to one.  Similarly w.Nbr must be compatible with DECIMAL(17).  If necessary Jazz will ensure that assignments to the exact format required by the routine are inserted before and after the CALL. 

 

A PARAMETERS definition is like any other DEFINE except with extra options INPUT, OUTPUT, or INOUT, and OPTIONAL for situations where a parameter is not always required.   Refer to

            Language Reference: The Define Statement

and      Users’ Guide: Jazz Logic/ External Routines

for more information

The INVOKE Statement

FUNCTION

To pass control and parameter[s] to another CICS or Web Service task. 

 

NOTE.  The CICS-form INVOKE statement has been partly developed, but has not been tested.  If you use it you’ll get an E-level message (#518) which asks you to check the COBOL, and to report any errors to Jazz Software

FORMAT

To invoke another CICS task: -

      INVOKE CICSName [(parameter)] [CONTINUE] [TRANSFER];

 

CICS-name follows the rules for external names, i.e. it must be eight characters or less, and may not contain a hyphen.  There will be one parameter, typically a COMMAREA definition.  For example

INVOKE CICS2(CICS2C);

 

To invoke a web service: -

            INVOKE Service-Name (Input parameter [,Input parameter]…)] REPLY(Output parameter [,Output Parameter]…)

 

Service-name is the name of a service that has been discovered, for example

INVOKE JZTst-SOATest1(WRK.Name) REPLY(wrk.result, wrk.Name );

 

INVOKE is like CALL in many ways: -

 

However in other ways it is different

CALL (or INVOKE) and Interface Definitions

When a CALL or INVOKE statement is encountered Jazz first looks for a corresponding DEFINE name with type PARAMETERS in the program. If it can’t find one it will attempt to find one in the Jazz CopyLib, and if necessary a COPY statement will be inserted.

 

From the interface definition Jazz can check that

1.                  If the subprogram is written for CICS, or BATCH, it is being called from the correct kind of program

2.                  There are the correct number of parameters,

3.                  That they have the correct formats and value,

4.                  For constants and INPUT parameters Jazz will assign the parameter value to a working-storage field of the correct format before invoking the subprogram, to ensure that its value doesn’t change in the calling program.

5.                  If necessary their value will be validated. For example, if a parameter is defined with VALIDVALUES then, unless the CALL closely follows an ACCEPT where the value has already been validated, code will be inserted before the CALL to ensure that the parameter has one of these values

 

In normal use the parameter names – X, Y, and Z in this example – are irrelevant: the CALL (or INVOKE) statement passes other fields (or groups) as arguments. In the earlier example we wrote: -

            DEFINE SubProg PARAMETERS CICS DATA(

                X SMALLINT,

                Y GROUP,

                  Y1 DECIMAL(3),

                  Y2 CHAR(10),

                Z MONEY(7,2));

           

            CALL SubProg(Work.A, Work.B.*, Work.C);

Hopefully the field named A within Work is defined as a SMALLINT, and so on. The group Work.B.* should contain two fields with appropriate format, but these do NOT have to be named Y1 and Y2.

CALL and TYPE(PARAMETERS CICS)

For CALL statements if the parameter definition includes CICS then two parameters are automatically inserted before any named parameters. These are DFHEIBLK and DFHCOMMAREA, special control areas used by CICS. Thus although we wrote

      CALL SubProg(Work.A, Work.B.*, Work.C);

above, at the COBOL level the generated CALL statement is

      CALL 'SubProg' USING DFHEIBLK DFHCOMMAREA A OF WORK B OF WORK C OF WORK.

Within the calling program you can ignore these parameters.  If you write SubProg directly in COBOL then you must remember to include them in the USING clause and define them (and A, B, and C) in the linkage section.  If you create SubProg with Jazz, then the SUBPROGRAM statement’s CICS option will ensure that they are included.

 

For INVOKE the parameter definition MUST include CICS or SOA. The parameters will be included automatically for CICS, but for SOA they must be given explicitly if they are wanted. Control is passed to other CICS programs via EXEC CICS LINK or EXEC CICS XCTL statements rather than CALL, and to web services with EXEC CICS INVOKE SERVICE.

Direct Reference to Parameter fields

When the program contains DEFINE name PARAMETERS DATA(… then a definition of these fields is created in working storage, just as if the DEFINE statement used TYPE(WORK). These fields will be initialised (VALUE clause, else zeros, blanks, etc), and you can use these fields in expressions in the same way as any other field of their type. This includes: you can directly name the parameter fields in the CALL (or INVOKE) statement: -

      CALL SubProg (SubProg.X, …

 

Obviously the use of a direct parameter reference ensures that the format is correct for the subprogram, but it is your responsibility to assign the appropriate value to the field before the CALL and assign it from the parameter field to the relevant field elsewhere in your program. Note however that if the parameter is defined with OUTPUT then the parameter field, SubProg.X in this example, will be initialised before the call, and any value that you have assigned to it before the CALL will be lost.

 

There will be a warning message if you directly name a parameter field defined with INPUT or OUTPUT.

 

If you’re using the parameter fields you should be aware that their value may be automatically reset by other CALL statements, so they should be treated as temporary fields and any output values should be assigned elsewhere as soon a possible.

Passing Constants

You can give constants as arguments, for example

      CALL SubProg (0, …

If the constant is invalid for the type (not a number in this case) there will be an error message, otherwise the constant will be assigned to the parameter field which will be passed to the subprogram. If the parameter is defined with OUTPUT or INOUT there will be a warning message.

 

If an optional parameter is omitted then the field in the parameter definition is set to its initial value and passed.

Passing other fields

With CALL SubProg(Work.A,… (or INVOKE) the behaviour of the CALL/INVOKE statement depends on the format of Work.A and whether it has been defined with INPUT, OUTPUT, or INOUT.   Thus with the parameters defined as before: -

            DEFINE SubProg PARAMETERS CICS DATA(

                X SMALLINT,

                Y GROUP,

                  Y1 DECIMAL(3),

                  Y2 CHAR(10),

                Z MONEY(7,2));

and a Call statement: -

            CALL SubProg(Work.A, Work.B.*, Work.C);

 

If Work.A has the same format as SubProg.X (in this example SMALLINT) and the parameter is defined with INOUT (which is implied if INPUT and OUTPUT are not given) then it is passed directly.  If Work.A is any other kind of number, or has been defined with INPUT or OUTPUT, then Jazz will pass the parameter by assignment: -

            IF the parameter is INPUT or INOUT THEN

                        The value of Work.A will be assigned to SubProg.X

            ELSE

                        SubProg.X is initialized

            END IF

            CALL SubProg (SubProg.X

            IF the parameter is INOUT or OUTPUT THEN

                        Assign SubProg.X to Work.a

            END IF

 

This allows you to CALL SubProg(any-number, …) with Jazz handling all the data conversion for you.

 

If Work.A is another kind of field then an assignment SubProg.X = Work.A would be invalid, so an error message is produced

 

For a parameter like Work.X to be passed directly it must not only be defined with INOUT, it must also have EXACTLY the same type as the corresponding field defined in the TYPE(PARAMETERS) definition. This means: -

1.                  The same type:  SMALLINT <-> SMALLINT, INTEGER <-> INTEGER, DECIMAL<-> DECIMAL, etc. For this purpose Jazz regards MONEY and DECIMAL as the same type: the only difference between these types is in their display format.

2.                  It must have the same number of digits, precision, and length.  Thus CHAR(10) and CHAR(11) are different, as are DECIMAL(5) and DECIMAL(4), or DECIMAL(5) and DECIMAL(5,2).

3.                  Groups must have exactly the same structure. Thus in

            CALL SubProg(Work.A, Work.B.*, Work.C);

Work.B must have a DECIMAL(3) element, followed by a CHAR(10) element, and no other elements. If Work.B were defined like this: -

            B GROUP,

                B1 DECIMAL(2),

                B2 CHAR(9),

                END GROUP,

then either the mismatch of B1 with Y1 or the mismatch of B2 with Y2 would have been sufficient to have implied “Different”. However this may be too strict in practice, so Jazz relaxes the rules a bit: -

Passing Group Parameters

If a group named in the CALL statement does not exactly match the parameter in the DEFINE, Jazz will still pass a group directly if the following rules are met: -

IF         the CALL/INVOKE statement names a CHAR field or a GROUP that contains only CHAR and PIC fields

AND

            The corresponding parameter is also a CHAR field or a group containing only CHAR and PIC fields,

AND

            The field/group named in the CALL has the same length as the Field/Group defined as parameter

THEN  Jazz produces a warning message, and will pass the parameter directly for INOUT, by assignment for INPUT or OUTPUT. This allows you to write code like this: -

            CALL Routine(PrintLine1);

           

            CALL Routine(Printline2);

Now you don’t have to worry whether Printline1 and Printline2 have the same structure, merely that they have the same total length.

 

Provided that the groups have the same length, if either the passed field or parameter definition contains fields other than CHAR and PIC then an error message is produced rather than a warning. You can ignore this message if you are confident that there will be no problems: Jazz will create a COBOL CALL statement that passes the group by reference.   However if there are differences – for example the CALL group contains a SMALLINT value where the DEFINE group specifies DECIMAL – then unpredictable results, probably an unrecoverable abend, will result.

 

If these rules are followed except that the parameter/passed field have a different length, then there will be a message and the parameter will be passed by assignment.  Group assignment follows CHAR rules: if the target is too short the data is truncated, if the data is too long it is extended with blanks.