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