CARMA Developer's Perspective

This paper describes the use of the RDz CARMA interface from the developer's perspective using as example the interface to DATEV's proprietary source management system ("SRCVW" = SouRCe VerWaltung). It does not describe the tasks that the system programmer must perform to create the required CARMA environment.

This paper is based on a session presented at an earlier Enterprise Modernisation conference. Although the methodology described in this paper was tested on WDz Version 6, the procedure is still generally valid (RDz 7.5).

SRCVW Characteristics:

SRCVW is USS based (administrative data, program source versions).

Each user (department, group, team, etc.) must define a project (and project version, currently, except for test projects, always 1.0).

Each program version exists as a unique HFS file.

This gives the following 4-level name structure:

<project>/<projectversion>/<programname>/<programversion>

For example:

SED/1.0/SETEST14/1.3

Interfaces (APIs):

SRCVW provides a TSO REXX procedure that routes the request to the appropriate service routine. Such service routines have both associated TSO REXX procedures and USS REXX procedures.

Project structure

The following figure illustrates a simple SRCVW project structure with the associated entities (connection, RAM, instance, member). The green arrow indicates an active connection.

The figure shows that MVSE001 connection has three RAMs: PDS RAM, SCLM RAM and SRCVW RAM. The first two RAMs are samples supplied with RDz. The customised SRCVW RAM used the RDz-supplied TEST RAM as basis.

Alternative project structure

It is also possible to define an alternative project structure that has an additional level 2 (project + project version). This allows containers to be defined at the next lower level.

Expanding the project level lists the associated programs.

Expanding a program (=container) lists the associated program versions.

Note: Which of these two structures is used is largely a personal preference.

RAM implementation

Characteristics:

The SRCVW RAM is a C program (RDz also supplies a sample COBOL program that could be customised).

Customised interfaces (C functions) were written to provide fast access to general SCM services (read-only) - list "directory" contents, list program, etc.

Standard SCM REXX execs used for "write" services (check out, …).
SRCVW RAM uses a wrapper to invoke these services.The wrapper (a user-written C function) invokes the REXX interpreter to call the specified SCM service. The SCM services return a result string that contains the service return code (non-zero return code -> error, the associated error text is contained in the result string). The wrapper parses this result string to evaluate the result.

Some RAM operations set a custom return value, for example, to explicitly confirm the end of the associated operation.

Typical CARMA RAM function

A typical CARMA RAM function has the following form:

int checkin(char instanceID[256], char memberID[256], void**params,

void***customReturn, char error[256]);

CARMA configuration

The use of CARMA requires that certain host-side configuration settings be made. These are primarily:

  • The creation of the CRADEF VSAM file.
  • The creation of the CRASTRS VSAM file.
  • The creation of the CARMA “job”.

These are described in more detail later and explained in the CARMA Developer’s Guide (SC29-7660).

Essentially, these configuration settings have the following purpose. The CRADEF file defines the load module name of the RAMs, which functions each RAM supports with the associated symbolic parameters and return values. The CRASTRS file supplies the associated translated text in the supported codepages for the entries defined in CRADEF.The CARMA job (batch TSO) starts when a connection to a CARMA repository is made and accepts the requests; the job terminates when a disconnection is made to the CARMA repository. This job must supply all DD statements required by the RAM.

The CARMA runtime uses the CRADEF and CRASTRS file content to generate the appropriate input/output masks.

Example of a dynamically generated input mask

The following input mask is generated when the Checkout action (action number 13) is invoked.

The CRADEF record for action 13 (Ann013 record) defines three input parameters (003, 004 and 005) and one return value (000). These have associated CRADEF record definitions Pnn003 … 005 and Tnn000, respectively (nnis the RAM number, in this case 02).

A02013 003,004,005!000

P02003 STRING 44 N

P02004 STRING 8 N

P02005 STRING 32 N

T02000 STRING 48

The associated CRASTRS records contain the national-language text to be displayed for each of these fields.

EN_US 00037P02003 DSN Dataset name?

EN_US 00037P02004 MEM Member name?

EN_US 00037P02005 OPTIONS Options?

EN_US 00037T02000 OK Completed successfully

CARMA RAM function parameters

The parameters passed to and returned from a specific CARMA function depend on the associated function and on the settings made in CRADEF (for example, the number of parameters and the form of the associated text).

The following parameters are used by many functions:

instanceIDidentifies the associated instance

memberIDidentifies the associated member

paramspointer to an array of associated parameters

customReturnpointer to an array of custom return values set by the function
Note: the actual return values must not be on the stack.

errora character string that contains descriptive text for an error
(non-zero function return value)

Descriptorreturned data records
(the number of returned records must be set in a separate field)

With the exception of Descriptor, which is a structure name, variable names are shown.

<params> and <customReturn> for the associated function implementation must be defined in CRADEF.

The associated <params> and <customReturn> displayed in a mask with the text specified for the associated function implementation must be defined in CRASTRS.

The Descriptor structure has the following fields

char id[256];

char name[64];

<id> is, in effect, a unique key

<name> is the displayed text.

Memory for returned data

Buffers for returned data must be allocated dynamically (in C, with malloc() ).

The CARMA host client frees the allocated (heap) memory.

ID structure

The ID must be unique (and not contain any 0x00s!; the presence of 0x00s can cause strange and unexpected behaviour).

The associated ID is returned for most CARMA functions
-> used to return the appropriate information from the SCM (via program logic (direct, indirect using a hash table, etc.))

My ID structure:

1<project>, e.g. 1SED

2<project>/<projectversion>, e.g. 2SED/1.0

3<project>/<projectversion>/<program>, e.g. 3SED/1.0/SETEST13

4<project>/<projectversion>/<program>/<programversion>, e.g. 4SED/1.0/SETEST13/1.2

This allows the associated data to be retrieved directly.

Note: It is important to map the logical structure of the SCM to an appropriate ID.

Actions

The CARMA functions are associated with an action ID. The functions can be customised for the specific RAM.This customisation is made in the CRADEF (and CRASTRS) VSAM-KSDS files (and obviously in the programmed RAM).

The following actions are available:

0initRam

1terminateRam

2getMembers

3extractMember

4putMember

5getAllMemberInfo

6getMemberInfo

7updateMemberInfo

8isMemberContainer

9getContainerContents

10lock

11unlock

12checkIn

13checkOut

14getInstances

15reset

16performAction (customised actions)

80initCarma

81terminateCarma

82getRAMList

83getRAMData

The actual actions (and their parameters and return values) supported by the RAM must be specified in the CRADEF file.

Actions (continued)

Although most actions are called implicitly (for example, initRam(), some actions are called explicitly (checkIn(), checkOut(), lock(), unlock(), custom()) from the instance context menu.

Other actions can be controlled by the RAM.

For example, isMemberContainer(). The answer Yes (=1)means the getContainerContents() action will be called when the corresponding entry is expanded.

Customised action

Customised actions can be defined for a RAM. Each customised action has its own unique ID (its action ID). Action IDs in the range 100 to 999 are used to define customised actions.

The performAction() function receives control when a customised action is invoked.

The function has four input arguments:

actionIDThe associated customised action ID

instanceIDThe instance ID

memberIDThe member ID

paramsThe parameters defined for the customised action ID. The parameters are entered in
the displayed prompt.

Extract from the CRADEF file

A02101 006|000,001

A02102 006|000

P02006 STRING 32 N

T02000 STRING 48

T02001 STRING 16

Positions 2-3 specify the associated RAM number; position 1 is the record type.

The associated CRASTRSentries:

EN_US 00037A02101 COMPILE

EN_US 00037A02102 RESET

EN_US 00037P02006 PARM Parameters

EN_US 00037T02000 OK Completed successfully

EN_US 00037T02001 RSC

Here positions 9-13 specify the codepage, and 14-16 the record type and RAM number.

Theseentries specify that RAM 02 (SRCVW) has two customised actions: 101 = COMPILE, 102 = RESET. Each of these actions has one input parameter (006) and one or two customised return values, respectively. The input parameter hasParametersas displayed text (the name PARM is not used).

COMPILE has two customised return values with namesOK as and RSC, respectively (the descriptions,Completed successfullyfor OK) are not used).

CRADEF schematic (for the first custom action)

┌─┬───┬─────┬───┬─────┬─┬─────────────┐

│A│0│2│1│0│1│ │0│0│6│|│0│0│0│,│0│0│1│

└┬┴─┬─┴─────┴───┴─────┴┬┴─────────────┘

│ │ └──┬──┘ └──┬──┘│└──────┬──────┘

│ │ │ │ │ │

│ │ │ │ │ └───────► Return value IDs (-> T record)

│ │ │ │ └───────────────► Delimiter (note: ! in German)

│ │ │ └───────────────────► Parameter IDs (-> P records)

│ │ │

│ │ └─────────────────────────────► Secondary ID (= custom Action ID)

│ │

│ └──────────────────────────────────► RAM ID

└─────────────────────────────────────► A = Action

Parameter entry

┌─┬───┬─────┬───┬──────┬───┬─┐

│P│0│2│0│0│6│ │STRING│32 │N│

└┬┴─┬─┴─────┴───┴──────┴─┬─┴┬┘

│ │ └──┬──┘ └───┬──┘│ │

│ │ │ │ │ └───────► N = not constant

│ │ │ │ │

│ │ │ │ └──────────► Parameter length

│ │ │ │

│ │ │ └───────────────► Parameter type

│ │ │

│ │ └──────────────────────────► Parameter ID

│ │

│ └───────────────────────────────► RAM ID

└──────────────────────────────────► P = Parameter

The associated CRASTRS entry (for brevity, without prefixed locale (EN_US) and code page (00037))

┌────────┬──────┬────────────┐

│P02006 │PARM│ Parameters │
└───┬────┴──┬───┴─────┬──────┘

│ │ │

│ │ └───────────────► Description

│ └─────────────────────────► Name (not used)

└─────────────────────────────────► Key

The associated display

Depending on whether COMPILE or RESET is double-clicked, customised actionID 101 or 102, respectively, will be passed to the processing function.

In this case, COMPILE (customised actionID 101) was selected for member SETEST13.

InstanceID: 2SEA/1.0

memberID: 4SEA/1.0/SETEST13/1.1

With the associated parameter prompt

Here 'alpha' is entered as parameter.

The first customised return value entry

┌─┬───┬─────┬───┬──────┬───┐

│T│0│2│0│0│0│ │STRING│48│

└┬┴─┬─┴─────┴───┴──────┴─┬─┘

│ │ └──┬──┘ └───┬──┘│

│ │ │ │ │

│ │ │ │ └──────────► Customised return value maximum length

│ │ │ └───────────────► Parameter type

│ │ └──────────────────────────► Parameter ID

│ └───────────────────────────────► RAM ID

└──────────────────────────────────► P = Parameter

The associated CRASTRS entry (for brevity, without prefixed locale (EN_US) and code page (00037))

┌────────┬────┬────────────────────────┐

│T02000│OK │ Completed successfully │
└───┬────┴─┬──┴───────────┬────────────┘

│ │ │

│ │ └───────────────► Description (not used)

│ └──────────────────────────────► Name (used in the display)

└─────────────────────────────────────► Key

With the associated return

The associated user-writtenperformAction() function

int performAction(int actionID, char instanceID[256],

char memberID[256], void** params,

void*** customReturn, char error[256]) {

char *pprocname;

char *ppj;

static char msg1[48];

static char msg2[16];

ppj = params[0]; // pointer to firstparameter

switch (actionID) { // process

case 101:

pprocname = "SESVCACT"; // Compile

break;

case 102:

pprocname = "SESVCRES"; // Reset

break;

default:

printf("invalid actionID: %d\n",actionID);

return 107;

}

presult = execREXXProcedure(pprocname,1,ppj);

rc = getRC(presult); // extract return code from result

printf("execREXXProcedure RC:%d\n",rc);

if (rc != 0) {

int n;

memset(error, ' ', 256);

n = MIN(strlen(presult),256);

memcpy(error,presult,n);

return 503;

}

switch (actionID) {

case 101: // compile

memset(msg2, ' ', sizeof(msg2));

memcpy(msg2, "Reason code: 47",15);

*customReturn = malloc(sizeof(void *) * 2);

(*customReturn)[1] = (void *)msg2;

break;

case 102: // reset

*customReturn = malloc(sizeof(void *) * 1);

break;

default:

}

memset(msg1, ' ', sizeof(msg1));

memcpy(msg1, "completed successfully",22);

(*customReturn)[0] = (void *)msg1;

return 0;

}

Note: Because the two custom actions return a different number of return values, to prevent memory leakage, it is important that the correct amount of memory is allocated for the customReturn vector.

Action custom parameters

The parameters to be passed to an action are specified in CRADEF (and CRASTRS).

When an action is invoked, the associated mask for the parameter input will be displayed.

Example

If the "Remember the entered values for later" box is ticked, the entered values will be retained for the associated entry. Some displayed text is generated automatically (based on the associated action), whereas the text associated with the parameters comes from the CRASTRS file.

Action function return values

An action can return two values:

  • the function direct return value
    (0 = success, otherwise error return code (optionally with text in <error>))
  • custom return value(s)

The function direct return value must be set.

If custom return values are set, the appropriate entries must be defined in CRADEF (and CRASTRS).

Many functions also return data.

Action function direct return value

A non-zero function return value indicates failure.

Both predefined return codes (for example, 20 = internal error) and user-defined return codes can be used (return codes in the range 500-900). User-defined return codes do not need to be defined in any CARMA control files. Appendix A of the CARMA Developer's Guide lists the predefined return codes.

The error message for a user-defined return code is generated based on the associated action function, the return code and the supplied text.

Example for setting a non-zero function return value

int checkin(char instanceID[256], char memberID[256], void**params,

void***customReturn, char error[256]) {

memset(error, ' ', 256);

pstr = "CKIN Function not supported";

memcpy(error, pstr, strlen(pstr));

return 507;

}

The associated display

Note: The extended error text is displayed when the mouse is positioned on the error message.

Action custom return value

Example of the use of a custom return value to indicate the successful processing of an action.

The appropriate heap memory must be allocated to contain the pointer to each custom return value (the number of custom return values and their respective maximum lengths are specified in the CRADEF entry from the associated action. In this case, one custom return value is returned.

Heap memory can be allocated dynamically with the malloc() function or statically as global variable or with the static attribute.

int performAction(int actionID, char instanceID[256],

char memberID[256], void**params,

void***customReturn, char error[256]) {

static char msg[49];

memset(msg, ' ', sizeof(msg)); // clear msg area

memcpy(msg, "Processing completed successfully", 34);

*customReturn = malloc(sizeof(void *) * 1);

(*customReturn)[0] = (void *)msg;

return 0; /* OK */

}

CARMA RAM job

CRASUBMT (in SCRACLST)

This job is started when the connection to CARMA is made, and terminated on disconnection (at the remote system level).

Example of a customised CRASUBMT job

PROC 1 PORT

SUBMIT * END($$)

//&SYSUID.1 JOB (accountinginformation),CARMASERV,

// MSGLEVEL=(1,1),MSGCLASS=V,TIME=(,20),CLASS=N,NOTIFY=&SYSUID

//* LICENSED MATERIALS - PROPERTY OF IBM *//

//ALLOC EXEC PGM=IEFBR14

//TEMP DD UNIT=3390,SPACE=(CYL,(1,1)),LRECL=80,RECFM=FB,DSORG=PS,

// DSN=&SYSUID..TEMP,

// BLKSIZE=0,DISP=(MOD,CATLG)

//*

//RUN EXEC PGM=IKJEFT01,DYNAMNBR=25,REGION=1024K

//STEPLIB DD DSN=CRA.V6.SCRALOAD,DISP=SHR

// DD DSN=REXX.V1R4.SEAGLPA,DISP=SHR

//CRADEF DD DSN=CRA.V6.VSAMV.CRADEF,DISP=SHR

//CRAMSG DD DSN=CRA.V6.VSAMV.CRAMSG,DISP=SHR

//CRASTRS DD DSN=CRA.V6.VSAMV.CRASTRS,DISP=SHR

//CRARAM1 DD DSN=CRA.V6.VSAMV.CRARAM1,DISP=SHR

//CRARAM2 DD DSN=CRA.V6.VSAMV.CRARAM2,DISP=SHR

//ISPPROF DD UNIT=3390,SPACE=(CYL,(2,2,2)),LRECL=80,RECFM=FB,DSORG=PO,

// BLKSIZE=3120,DISP=(NEW,DELETE)

//SYSUDUMP DD SYSOUT=V

//*

//* DD:TEMP work file required for DATEV SRCVW CARMA interface

//TEMP DD DSN=&SYSUID..TEMP,DISP=(OLD)

//SYSPROC DD DSN=SYS1.SBPXEXEC,DISP=SHR

// DD DSN=SYS1.SISPCLIB,DISP=SHR

// DD DSN=TSSE000.FSET.EXEC,DISP=SHR

// DD DSN=TSRCVW.SRCVW.DIALOG,DISP=SHR

//ISPEXEC DD DSN=SYS1.SISPEXEC,DISP=SHR

//ISPPLIB DD DSN=SYS1.SBPXPENU,DISP=SHR

//ISPMLIB DD DSN=SYS1.SBPXMENU,DISP=SHR

//ISPSLIB DD DSN=SYS1.SISPSLIB,DISP=SHR

//ISPTLIB DD DSN=SYS1.SBPXTENU,DISP=SHR

//SYSTSPRT DD SYSOUT=*

//SYSTSIN DD *

ISPSTART +

PGM(CRASERV) PARM(&PORT)

//

$$

EXIT CODE(0)

Italics = DATEV extension to the CRASUBMT job.

Red = CARMA files.

Note: The DLL with the user-written RAM must be contained in one of the libraries specified in the STEPLIB concatenation.

CARMA control files

CARMA has several VSAM control files (see CRASUBMT).

The two VSAM control files of direct interest for the RAM programmer are:

  • CRADEF (language-independent CAF (Custom Action Framework) data)
  • CRASTRS (language-dependent CAF data)

These files will normally need to be customised for the RAM.

CRADEF

Language-independent CAF data (one record for each CAF object type: A = action, P = parameter, R = RAM, T = return value)

A01004 001,003!

A01010 001,002!

A01011 001,002!

A01014 000!

A01100 001,004,005!

A01101 001,004,005!

A02004 003,004!

A02013 003,004,005!000

A02014 000,001,002!

A02101 006!000,001

A02102 006!000

D02010

P01000 STRING 16 N

P01001 STRING 16 N

P01002 STRING 16 N

P01003 STRING 16 N

P01004 STRING 1 N

P01005 STRING 1 N

P02000 STRING 8 N

P02001 STRING 8 N

P02002 STRING 8 N

P02003 STRING 44 N

P02004 STRING 8 N

P02005 STRING 32 N

P02006 STRING 32 N

R00000 1.1 C Z/OSV1R41.0 CRARPDS

R01000 1.0 C 1.0 1.0 CRARSCLM

R02000 1.0 C Z/OSV1R61.0 RUDDRAM

T02000 STRING 48

T02001 STRING 16

CRASTRS

Language-dependent CAF data.

Each CRADEF record has a corresponding CRASTRS record for each language, even when the CRASTRS record does not contain any text.

EN_US 00037A01004

EN_US 00037A01010

EN_US 00037A01011

EN_US 00037A01014

EN_US 00037A01100 BUILD

EN_US 00037A01101 PROMOTE

EN_US 00037A02004

EN_US 00037A02009

EN_US 00037A02013

EN_US 00037A02014

EN_US 00037A02101 COMPILE

EN_US 00037A02102 RESET

EN_US 00037D02010

EN_US 00037P01000 PROJECT What is the project name?

EN_US 00037P01001 PROJDEF What is the project definition?

EN_US 00037P01002 ACCESS Access?

EN_US 00037P01003 LANGUAGE What is the language?

EN_US 00037P01004 SCOPE N What is the scope?

EN_US 00037P01005 MODE C What is the mode?

EN_US 00037P02000 PROJECT Project name?

EN_US 00037P02001 PV Project version?

EN_US 00037P02002 PGM Program name?

EN_US 00037P02003 DSN Dataset name?

EN_US 00037P02004 MEM Member name?

EN_US 00037P02005 OPTIONS Options?

EN_US 00037P02006 PARM Parameters

EN_US 00037R00000 PDS RAM Allows browsing of PDSs and browsing/modification

EN_US 00037R01000 SCLM RAM Capable of performing all CARMA API actions

EN_US 00037R02000 SRCVW RAM My test RAM;

EN_US 00037T02000 OK Completed successfully

EN_US 00037T02001 RSC

Schematic relationship between CRADEF entries (simplified)

CRADEF

A RAM definition

┌─┬───┬─────┬───┬───┬─┬────────┬───┬───────┐

│R│0│2│0│0│0│ │1.0│C│Z/OSV1R6│1.0│RUDDRAM│
└┬┴─┬─┴──┬──┴───┴─┬─┴┬┴────┬───┴─┬─┴───┬───┘

│ │ │ │ │ │ │ │

│ │ │ │ │ │ │ └──────► DLL name

│ │ │ │ │ │ │

│ │ │ │ │ │ └────────────► CARMA version

│ │ │ │ │ │

│ │ │ │ │ └──────────────────► Repository version

│ │ │ │ │

│ │ │ │ └────────────────────────► Programming language (C,COBOL,PLI)

│ │ │ │

│ │ │ └───────────────────────────► RAM version

│ │ │

│ │ └────────────────────────────────────► '000'

│ │

│ └─────────────────────────────────────────► RAM ID

└────────────────────────────────────────────► R = RAM (record type

The associated CRASTRS entry

┌────────┬───────────┬──────────────┐

│R02000 │ SRCVW RAM │ My test RAM; │
└───┬────┴─────┬─────┴──────┬───────┘

│ │ │

│ │ └──────────────► Description

│ │

│ └───────────────────────────► Name (= repository type)

└──────────────────────────────────────► Key

The associated DATEV RAM properties (from the context menu)

Disabled Action entry

An Action entry is customised to specify the input parameters and return values.

Extract from the CRADEF file.

D02010

Associated CRASTRSentry:

EN_US 00037D02010

CRADEF schematic