i2Zeebe

From i2Rest
Jump to: navigation, search

i2Zeebe works as a bridge between IBM i server and Zeebe process automation engine. You can use i2Zeebe as a native equivalent of zbctl utility or as Zeebe client library for use in your ILE RPG/C code. i2Zeebe represents IBM i program written on ILE C, which can be called from command line or from any IBM i program. With i2Zeebe, you can interact with almost any Zeebe API (gRPC) directly from IBM i server.

What is Zeebe

According to the vendor, Zeebe is the workflow and decision engine that powers Camunda. Zeebe's cloud-native design provides the performance, resilience, and security enterprises need to future-proof their process orchestration efforts.

Quote:
With Zeebe you can:

  • Define processes graphically in BPMN 2.0.
  • Choose any gRPC-supported programming language to implement your workers.
  • Build processes that react to events from Apache Kafka and other messaging platforms.
  • Use as part of a software as a service (SaaS) offering with Camunda Platform 8 or deploy with Docker and Kubernetes (in the cloud or on-premises) with Camunda Platform 8 Self-Managed.
  • Scale horizontally to handle very high throughput.
  • Rely on fault tolerance and high availability for your processes.
  • Export processes data for monitoring and analysis (currently only available through the Elasticsearch exporter added in Camunda Platform 8 Self-Managed).
  • Engage with an active community.

For documentation on deploying Zeebe as part of Camunda Platform 8 Self-Managed, refer to the deployment guide.

What is i2Zeebe

i2Zeebe is native IBM i program which combines abilities of Zeebe CLI client and Zeebe client library for use on IBM i server platform. It uses parameters passed from command line or from calling program, to perform interaction to Zeebe process engine.

Examples of i2Zeebe usage

Command line interface

Topology request

call i2zeebe parm('Topology' '--gateway' 'http://gateway:26500' '--sync' '--printResponse=joblog')

Depending on your Zeebe cluster configuration, this call will produce information in the job log like this (formatted here for clarity):

{
  "http2_status": 200,
  "http2_error": 0,
  "grpc_status": 0,
  "TopologyResponse": {
    "brokers": [
      {
        "nodeId": 0,
        "host": "node0",
        "port": 26501,
        "partitions": [
          {
            "partitionId": 1,
            "role": "follower",
            "health": "healthy"
          },
          {
            "partitionId": 2,
            "role": "follower",
            "health": "healthy"
          },
          {
            "partitionId": 3,
            "role": "follower",
            "health": "healthy"
          }
        ],
        "version": "8.2.7"
      },
      {
        "nodeId": 1,
        "host": "node1",
        "port": 26501,
        "partitions": [
          {
            "partitionId": 1,
            "role": "follower",
            "health": "healthy"
          },
          {
            "partitionId": 2,
            "role": "leader",
            "health": "healthy"
          },
          {
            "partitionId": 3,
            "role": "follower",
            "health": "healthy"
          }
        ],
        "version": "8.2.7"
      },
      {
        "nodeId": 2,
        "host": "node2",
        "port": 26501,
        "partitions": [
          {
            "partitionId": 1,
            "role": "leader",
            "health": "healthy"
          },
          {
            "partitionId": 2,
            "role": "follower",
            "health": "healthy"
          },
          {
            "partitionId": 3,
            "role": "leader",
            "health": "healthy"
          }
        ],
        "version": "8.2.7"
      }
    ],
    "clusterSize": 3,
    "partitionsCount": 3,
    "replicationFactor": 3,
    "gatewayVersion": "8.2.7"
  }
}

Activate jobs

Lets assume that we have published simple business process with service task that has type I2ZEEBE to our Zeebe cluster (http://gateway:26500):
I2zeebe simple.png
Now we can start the process, for example from Camunda Modeler (press Start process button in the bottom of Modeler interface:
I2zeebe simple start.png

At this step, Zeebe process engine should start the process and wait for activation of I2ZEEBE task by some worker. Let's do it from IBMi command line interface:
call i2zeebe parm('ActivateJobs' '--sync' '--printResponse' '--gateway' 'http://gateway:26500' '--jobType' 'I2ZEEBE' '--worker' 'I2ZEEBE')

Resulting job log:

{
  "http2_status": 200,
  "http2_error": 0,
  "grpc_status": 0,
  "ActivateJobsResponse": {
    "jobs": [
      {
        "key": 6755399441390948,
        "type": "I2ZEEBE",
        "processInstanceKey": 6755399441390943,
        "bpmnProcessId": "i2Zeebe_simple",
        "processDefinitionVersion": 1,
        "processDefinitionKey": 2251799814019882,
        "elementId": "i2Zeebe_task",
        "elementInstanceKey": 6755399441390947,
        "customHeaders": "{}",
        "worker": "I2ZEEBE",
        "retries": 3,
        "deadline": 1693331966076,
        "variables": "{}"
      }
    ]
  }
}


Job has been activated for our job worker I2ZEEBE for 30 seconds (default value of --timeout).

CompleteJob

Now we will complete job activated on the previous step.
call i2zeebe parm('CompleteJob' '--gateway' 'http://gateway:26500' '--sync' '--printResponse' 'joblog' '--jobKey' '6755399441390948')

Joblog shows the response:

{
  "http2_status": 200,
  "http2_error": 0,
  "grpc_status": 0,
  "CompleteJobResponse": {}
}                                                               

Call from ILE C program

When using as Zeebe client library, i2Zeebe supports two modes of parameters passing - RPG mode and Shell mode. We will demonstrate shell mode here:

// Example how to use i2Zeebe to communicate with Zeebe gateway
// 
// To compile:
// CRTCMOD MODULE(I2ZEEBE/EXAMPLE1) SRCFILE(I2ZEEBE/QCLESRC) DBGVIEW(*ALL)
// CRTPGM PGM(I2ZEEBE/EXAMPLE1) ACTGRP(*CALLER)
//
// To call:
// ADDLIBLE I2ZEEBE
// CALL EXAMPLE1

#include <stdio.h>
#include <qp0ztrc.h>        // Qp0zLprintf

#include "i2zeebe_h"

// Zeebe gateway address
#define GATEWAY "http://gateway:26500"

int main(int argc, char *argv[]) {

   i2ZeebeTopologyResponse_t TopologyResponse;
   int grpc_status;
   int nghttp2_error;
   int http2_status;
   char grpc_message[1000];
   int grpc_message_len=sizeof(grpc_message);

   // Get Zeebe cluster status information
   I2ZEEBE("Topology", 
           "--sync",
           "--gateway", GATEWAY,
           "--printResponse", "joblog",
           "--response", &TopologyResponse,
           "--grpcStatus", &grpc_status,
           "--nghttp2Error", &nghttp2_error,
           "--http2Status", &http2_status,
           "--grpcMessage", grpc_message,
           "--grpcMessageLen", grpc_message_len);

   Qp0zLprintf("Zeebe gateway version: %s\n", TopologyResponse.gatewayVersion);

   // Cleanup memory allocated by previous call
   I2ZEEBE("Cleanup", "Topology", &TopologyResponse);

   return 0;
}

Call from ILE RPG program

To call i2Zeebe from RPGLE program, it is recommended to pass parameters in RPG mode. In this mode, i2Zeege accepts fixed number of parameters - 5 for applying some action or 2 for releasing data allocated by the action:

      * Example how to use i2Zeebe to communicate with Zeebe gateway
      * 
      * To compile:
      * CRTRPGMOD MODULE(I2ZEEBE/EXAMPLE1) SRCFILE(I2ZEEBE/QRPGLESRC) DBGVIEW(*ALL)
      * CRTPGM PGM(I2ZEEBE/EXAMPLE1) ACTGRP(*CALLER)
      *
      * To call:
      * ADDLIBLE I2ZEEBE
      * CALL EXAMPLE1

     D gatewayVersion  S             50a

      /Copy i2ZeebeCpy
      /Free

        i2ZeebeCommon.gateway = 'http://gateway:26500'+x'00';
        i2ZeebeCommon.printResponse = 1;
        i2ZeebeCommon.syncCall = 1;

        I2ZEEBE(i2ZeebeTopology:
                i2ZeebeCommon:
                *NULL:
                %Addr(i2ZeebeTopologyResponse):
                *NULL);

        gatewayVersion = %Str(i2ZeebeTopologyResponse.gatewayVersion);
        DSPLY gatewayVersion;

        I2ZEEBEX(i2ZeebeTopology:
                %Addr(i2ZeebeTopologyResponse));

         Return;
      /End-Free

Zeebe Job Worker

i2Zeebe supports synchronous and asynchronous communications with Zeebe gateway. It allows to build native IBMi Zeebe job workers, as shown below (assuming happy path only; compiled program object name is EXAMPLE2):

// Example how to use i2Zeebe in Worker mode
// 
// To compile:
// CRTCMOD MODULE(I2ZEEBE/EXAMPLE2) SRCFILE(I2ZEEBE/QCLESRC) DBGVIEW(*ALL)
// CRTPGM PGM(I2ZEEBE/EXAMPLE2) ACTGRP(*CALLER)
//
// To call:
// ADDLIBLE I2ZEEBE
// CALL EXAMPLE2

#include <stdio.h>
#include <qp0ztrc.h>        // Qp0zLprintf
#include <mih/rslvsp.h>     // rslvsp

#include "i2zeebe_h"

// Zeebe gateway address
#define GATEWAY "http://gateway:26500"
#define JOBTYPE "I2ZEEBE"

static _SYSPTR example2 = NULL;

int main(int argc, char *argv[]) {

   int first_call = 0;
   int i;

   if(!example2) {
      first_call = 1;
      example2 = rslvsp(_Program, "EXAMPLE2", "*LIBL", _AUTH_NONE);
   }

   if(!first_call) {

      i2ZeebeActivateJobsResponse_t *response = (void *)argv[2];
      char activatedJob[20];
      
      for(i=0;i<response->jobs_count;i++) {
         sprintf(activatedJob, "%lld", response->jobs[i].key);
         Qp0zLprintf("Completing %s\n", activatedJob);
         I2ZEEBE("CompleteJob",
                 "--gateway", GATEWAY,
                 "--printResponse", "joblog",
                 "--jobKey", activatedJob,
                 "--variables", "{\"someData\":123}");
      }
   }

   I2ZEEBE("ActivateJobs", 
           "--gateway", GATEWAY,
           "--jobType", JOBTYPE,
           "--responseExit", &example2);

   if(first_call) I2ZEEBE("Resume");

   return 0;
}

Quickstart

Installation

  1. Download file i2Zeebe_Install.ZIP
  2. Put it to your home directory or to any other folder on IFS
  3. Open emulator session and run following commands:
    1. CHGCURDIR <directory_where_ZIP_copied>
      you'll see message "Current directory changed."
    2. QSH CMD('jar xMvf i2Zeebe_Install.ZIP')
      It will extract SAVF from zipped file, you'll see message "inflated: I2ZEEBE.SAVF"
    3. CRTSAVF FILE(QTEMP/I2ZEEBE)
      File I2ZEEBE created in library QTEMP.
    4. CPYFRMSTMF FROMSTMF(i2zeebe.savf) TOMBR('/qsys.lib/qtemp.lib/i2zeebe.file') MBROPT(*REPLACE)
      "Stream file copied to object."
    5. RSTLICPGM LICPGM(0AI2R10) DEV(*SAVF) SAVF(QTEMP/I2ZEEBE)
      *PGM objects for product 0AI2R10 option *BASE release *FIRST restored.
  4. Verify i2Zeebe installed:
    1. WRKLICINF PRDID(0AI2R10)
      i2Rest IBMi Zeebe client should be displayed
    2. WRKOBJPDM I2ZEEBE
      You'll see objects in I2ZEEBE product library

Start Zeebe instance

If you don't have Zeebe instance available yet, the easiest way to start playing with standalone Zeebe is to install it using Docker compose, as described in official documentation

All we need to continue is access to Zeebe gRPC services from our IBMi server. We need network access to the Zeege gateway server and port on which the Zeebe listens for gRPC requests (typically it is port 26500).

Show Zeebe status

Assuming that Zeebe server is accessible as 'gateway', we can try to call Zeebe to get its status, as described above:

call i2zeebe parm('Topology' '--gateway' 'http://gateway:26500' '--sync' '--printResponse=joblog')

i2Zeebe parameters

Depending on the programming language used, it is possible to pass parameters to the i2Zeebe in two different ways - Sell mode and RPGLE mode.

Using the first mode is more convenient when calling from command line or from programs written on ILE C language. It is preferred way of calling i2Zeebe.

The second mode called RPGLE mode is more convenient for calling from ILE RPGLE programs. In this mode, we tried to eliminate operations with pointers, at least in the input parameters. However, there are some restrictions on working with strings in this mode. As a rule, all input strings passed to the program in RPGLE mode are passed as fixed-length strings, and it is not possible to extend it lengths. One exception - parameter 'variables', it is the last parameter in input structures, and you are able to alter its default length in copysource I2ZEEBECPY or in your own copy of this copysource.

In any case, in both modes, all strings in the input and output parameters are null-terminated strings.

Memory allocation. When called with '--response' parameter (Shell) or with not-null value of 4th parameter 'response' (RPGLE), i2Zeebe will allocate all necessary subfields of response data structure in memory. It is required to deallocate this storage after using with call to 'Cleanup' command (Shell) or I2ZEEBEX procedure as defined in I2ZEEBECPY copysource. If response parameter is not specified, i2Zeebe will use internal data structures where needed, and will deallocate required temporary storage by himself.

Shell mode

In Shell mode, calling format is following:

Command line/QCMD:

call i2Zeebe parm(<Command> [command-specific options] [common options])

When calling from command line, all parameters, including numeric values, should represent null-terminated trimmed strings and should be enclosed to single quotas. Please pay attention that some parameters can not be specified when calling from command line, for example pointers to response data etc.

From QShell:

i2Zeebe <Command> [command-specific options] [common options]

From programs:

See example above.


Common options

Option Description
--gateway <address> Required for all commands, with except for Cleanup, Pause and Resume. Specifies address of Zeebe gateway, for example
--gateway http://gateway:26500
--sync This parameter tells i2Zeebe to run in synchronous mode, ie return to caller after receiving response from Zeebe
--async This is default calling mode. Can be omitted
--printResponse [joblog|stdout] Can be used for reporting/logging purposes. If defined, it can specify the way of logging Zeebe response. Valid sub options:
  • joblog (default and can be omitted if --printResponse specified). Zeebe response will be send to job log.
  • stdout - response will be printed in standard output
--response <address> May be used only when calling from programs.

Address specifies the pointer to the structure which will be filled with Zeebe response. Format of the structure depends on the called command.

All available response formats described in i2zeebe.h C include file and i2zeebe.copyr RPGLE copy source

When needed, i2Zeebe allocates storage for subfields of the response structure. It required to call Cleanup command after using the data, to release the allocated memory

--grpcStatus <address> May be used only when calling from programs.

Address specifies the pointer to long (10I 0 in RPGLE) value to store gPRC status of Zeebe response. gRPG statuses are described here

--http2Status <address> May be used only when calling from programs.

Address specifies the pointer to long (10I 0 in RPGLE) value to store http2 status of Zeebe response. Http2 status codes are described here

--nghttp2Error <address> May be used only when calling from programs.

Address specifies the pointer to long (10I 0 in RPGLE) value to store nghttp2 error code. i2Zeebe uses nghttp2 library for communications with Zeebe. nghttp2 error codes can be find here

--grpcMessage <address> May be used only when calling from programs.

Address specifies the pointer to string value to store text of gRPC error message. Should be used in conjunction with --grpcMessageLen option

--grpcMessageLen <length> May be used only when calling from programs.

Specifies how many bytes are available at --grpcMessage to store message text. Length has to be specified as null terminated string value ie "12345" in C or '12345' in RPGLE.

--responseExit <address> May be used only when calling from programs.

Specifies address which contained resolved system pointer to program which will be used as callback when processing Zeebe response. See example.

--userData <address> May be used only when calling from programs.

Specifies address of user data that will be passed to the response exit callback when processing Zeebe response. Can be used to store some application specific data which should be visible at request and response processing.

Command specific options

Command Options Description
ActivateJobs
  • --jobType <string> - Mandatory. Type of job to be activated
  • --worker <string> - worker name. Optional, default = "I2ZEEBE"
  • --timeout <number> - Timeout value. Null terminated string containing long long numeric value of timeout in milliseconds. Optional, default = "300000" (5m)
  • --requestTimeout <number> - Request timeout value. Null terminated string containing long long numeric value of timeout in milliseconds. Optional, default = "10000" (10s)
  • --maxJobsToActivate <number> - Maximum number of jobs to activate. Null terminated string containing long numeric value. Optional, default = "1"
  • --fetchVariable <string> - Name of variable to fetch during job activation. Can be specified several times.
[Documentation]
BroadcastSignal
  • --signalName <string> - Mandatory. Signal name to broadcast
  • --variables <json string> - Optional. Variables that has to be associated with the signal. Null-terminated string contains serialized data in Json format.
[Documentation]
CancelProcessInstance
  • --processInstanceKey <number> - Mandatory. Process instance key. Null-terminated string that contains long long number.
[Documentation]
CompleteJob
  • --jobKey <number> - Mandatory. The unique job identifier, as obtained from ActivateJobs response. Null-terminated string that contains long long number.
  • --variables <json string> - Optional. Variables that has to be set on job completing. Null-terminated string contains serialized data in Json format.
[Documentation]
CreateProcessInstance
  • --processDefinitionKey <number> - Optional. Unique key identifying the process definition. Null-terminated string that contains long long number.
  • --bpmnProcessId <string> - Optional. The BPMN process ID of the process definition. It is required to define one - processDefinitionKey or bpmnProcessId (and optionally version) to specify desired process definition
  • --version <number> - Optional. The version of the process; set to -1 to use the latest version. Null-terminated string that contains long number.
  • --variables <json string> - Optional. Variables that has to be set on job completing. Null-terminated string contains serialized data in Json format.
[Documentation]
CreateProcessInstanceWithResult
  • --requestTimeout <number> - Timeout (in ms, optional). The request will be closed if the process is not completed before the requestTimeout. If requestTimeout = 0, uses the generic requestTimeout configured in the gateway. Null-terminated string that contains long long number.
  • --processDefinitionKey <number> - Optional. Unique key identifying the process definition. Null-terminated string that contains long long number.
  • --bpmnProcessId <string> - Optional. The BPMN process ID of the process definition. It is required to define one - processDefinitionKey or bpmnProcessId (and optionally version) to specify desired process definition
  • --version <number> - Optional. The version of the process; set to -1 to use the latest version. Null-terminated string that contains long number.
  • --variables <json string> - Optional. Variables that has to be set on job completing. Null-terminated string contains serialized data in Json format.
[Documentation]
EvaluateDecision
  • --decisionKey <number> - Optional. The unique key identifying the decision to be evaluated. Null-terminated string that contains long long number.
  • --decisionId <string> - Optional. The ID of the decision to be evaluated. It is required to define one - decisionKey or decisionId to specify desired decision definition
  • --variables <json string> - Optional. Variables that will work as a context during decision evaluation. Null-terminated string contains serialized data in Json format.
[Documentation]
FailJob
  • --jobKey <number> - Mandatory. The unique job identifier, as obtained when activating the job. Null-terminated string that contains long long number.
  • --retries <number> - Optional. The amount of retries the job should have left. Null-terminated string that contains long number.
  • --errorMessage <string> - Optional. The message describing why the job failed
  • --retryBackOff <number> - Optional. The backoff timeout (in ms) for the next retry. Null-terminated string that contains long long number.
  • --variables <json string> - Optional. Null-terminated string contains serialized data in Json format.
[Documentation]
PublishMessage
  • --name <string> - Optional. Name of the message
  • --correlationKey <string> - Optional. The correlation key of the message.
  • --timeToLive <number> - Optional. How long the message should be buffered on the broker, in milliseconds. Null-terminated string that contains long long number.
  • --messageId <string> - Optional. The unique ID of the message. Only useful to ensure only one message with the given ID will ever be published (during its lifetime)
  • --variables <json string> - Optional. Null-terminated string contains serialized data in Json format.
[Documentation]
ThrowError
  • --jobKey <number> - Mandatory. The unique job identifier, as obtained when activating the job. Null-terminated string that contains long long number.
  • --errorCode <string> - Mandatory. The error code that will be matched with an error catch event
  • --errorMessage <string> - Optional. Error message that provides additional context
  • --variables <json string> - Optional. Null-terminated string contains serialized data in Json format.
[Documentation]
Topology [Documentation]
Cleanup
  • <request type> - Mandatory. 'Cleanup' is the special command of i2Zeebe which is not related with Zeebe gRPC API. It is used to free data, allocated by previous call to some request. You should call i2Zeebe in deallocate mode only in case of --response parameter was specified during call in normal 'Submit request' mode.

Example - see here.

RPGLE mode

In RPGLE mode, it is possible to call I2ZEEBE with two lists of parameters:

  • 'Submit request' parameters list used to call i2Zeebe to submit request to Zeebe
  • 'Deallocate' parameter list - to call i2Zeebe to free storage allocated in 'Submit request' mode

'Submit request' parameters list consists of 5 parameters, as defined in the prototype:

      * Submit request mode
     D I2ZEEBE         PR                  EXTPGM('I2ZEEBE')                                       
     D  Format                        7a   Const                                                   
     D  Common                             Const LikeDS(i2ZeebeCommon)                             
     D  request                        *   Const                                *Null/pointer to DS
     D  response                       *   Const                                *Null/pointer to DS
     D  responseExit                   *   Const                                *Null/ptr to SYSPTR

Parameters:

  • Format - string value which describes the format of request and response structures. Valid values (defined in I2ZEEBECPY as constants):
    • I2Z0100 - i2ZeebeActivateJobs
    • I2Z0200 - i2ZeebeBroadcastSignal
    • I2Z0300 - i2ZeebeCancelProcessInstance
    • I2Z0400 - i2ZeebeCompleteJob
    • I2Z0500 - i2ZeebeCreateProcessInstance
    • I2Z0600 - i2ZeebeCreateProcessInstanceWithResult
    • I2Z0700 - i2ZeebeEvaluateDecision
    • I2Z0900 - i2ZeebeFailJob
    • I2Z0A00 - i2ZeebePublishMessage
    • I2Z0D00 - i2ZeebeThrowError
    • I2Z0E00 - i2ZeebeTopology
     D i2ZeebeCommon   DS                  Qualified Inz                                            
     D  gateway                     512A                                        Url of Zeebe gateway
     D  userData                       *                                        Pointer to user data
     D  verbose                      10I 0                                      Verbose? 1:0
     D  printResponse                10I 0                                      Print response 0:1:2 no:joblog:stdout
     D  syncCall                     10I 0                                      syncCall 0:1 async:sync
     D  http2Status                  10I 0                                      output
     D  nghttp2Error                 10I 0                                      output
     D  grpcStatus                   10I 0                                      output
     D  grpcMessage...
     D   Length                      10I 0 Inz(256)                             input-length of msg
     D  grpcMessage                 256A                                        output
  • request - *Null or pointer to the structure with request-related fields. Structure depends on the request format. All formats are defined in I2ZEEBECPY copysource (i2Zeebe*Request data structures).
  • response - *Null or pointer to the structure where i2Zeebe will place gateway response. Structure depends on the request format. All formats are defined in I2ZEEBECPY copysource (i2Zeebe*Response data structures).
  • responseExit - *Null or pointer to resolved system pointer of the program which will be called by i2Zeebe to process the response. To resolve the system pointer, please use rslvsp API. Response exit *PGM should accept parameters defined by the following prototype or by similar *ENTRY PLIST:
     D responseExit    PR                                                                          
     D  userData                       *   Const                                user data          
     D  response                       *   Const                                i2Zeebe*Response DS
     D  grpcStatus                   10i 0 Const                                                   
     D  http2Status                  10i 0 Const                                                   
     D  nghttp2Error                 10i 0 Const                                                   
     D  grpcMessage                 256a   Const                                                   

Response exit program should process response message and make relevant actions. For example, if it called as ActivateJobs response exit, it can call i2Zeebe to CompleteJob, FailJob or ThrowError. After this, the response exit program can call i2Zeebe to ActivateJobs again.

'Deallocate' parameter list consists of 2 parameters, as defined in the prototype:

      * Deallocate mode
     D I2ZEEBEX        PR                  EXTPGM('I2ZEEBE')
     D  Format                        7A   Const
     D  response                       *   Const                                *Null/pointer to DS
  • Format - the same value as in the 'Submit request' parameter list
  • response - pointer to the i2Zeebe*Response structure which has been filled by i2Zeebe with response data

You should call i2Zeebe in deallocate mode only in case of 'response' parameter was not *Null during call in normal 'Submit request' mode.

i2Zeebe binaries

Link to download i2Zeebe binaries compiled on version IBMi V7R3M0:

i2Zeebe_Install.ZIP

Installation instructions: Installation

Header files

All sources that are required for compiling programs using i2Zeebe are located in the product library I2ZEEBE: I2ZEEBE/QRPGLESRC for RPGLE copysources and I2ZEEBE/QCLESRC for ILE C include files.

Files are also available here: i2zeebe.copyr and i2zeebe.h

Questions?

Questions? Issues? Found a bug? Need a consultation? Contact us!