Enterprise Modernisation CARMA Developer's Perspective Anthony Rudd (anthony.rudd@datev.de) © DATEV eG August 2009 CARMA Developer's Perspective ( © A. Rudd, Datev eG) 1 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. CARMA Developer's Perspective ( © A. Rudd, Datev eG) 2 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. Connection RAM Instance Member CARMA Developer's Perspective ( © A. Rudd, Datev eG) 3 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. Connection RAM Instance Container Member Note: Which of these two structures is used is largely a personal preference. CARMA Developer's Perspective ( © A. Rudd, Datev eG) 4 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 Developer's Perspective ( © A. Rudd, Datev eG) 5 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 (SC297660). 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. CARMA Developer's Perspective ( © A. Rudd, Datev eG) 6 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 (nn is the RAM number, in this case 02). A02013 003,004,005!000 P02003 P02004 P02005 STRING STRING STRING 44 8 32 T02000 STRING 48 N N N The associated CRASTRS records contain the national-language text to be displayed for each of these fields . EN_US EN_US EN_US 00037P02003 00037P02004 00037P02005 DSN MEM OPTIONS EN_US 00037T02000 OK Dataset name? Member name? Options? Completed successfully CARMA Developer's Perspective ( © A. Rudd, Datev eG) 7 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: <instanceID> <memberID> <params> <customReturn> <error> Descriptor identifies the associated instance identifies the associated member pointer to an array of associated parameters pointer to an array of custom return values set by the function Note: the actual return values must not be on the stack. a character string that contains descriptive text for an error (non-zero function return value) returned 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. CARMA Developer's Perspective ( © A. Rudd, Datev eG) 8 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. CARMA Developer's Perspective ( © A. Rudd, Datev eG) 9 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: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 80 81 82 83 initRam terminateRam getMembers extractMember putMember getAllMemberInfo getMemberInfo updateMemberInfo isMemberContainer getContainerContents lock unlock checkIn checkOut getInstances reset performAction (customised actions) initCarma terminateCarma getRAMList getRAMData The actual actions (and their parameters and return values) supported by the RAM must be specified in the CRADEF file. CARMA Developer's Perspective ( © A. Rudd, Datev eG) 10 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. CARMA Developer's Perspective ( © A. Rudd, Datev eG) 11 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: actionID instanceID memberID params The associated customised action ID The instance ID The member ID The parameters defined for the customised action ID. The parameters are entered in the displayed prompt. Extract from the CRADEF file A02101 A02102 006|000,001 006|000 P02006 STRING 32 T02000 T02001 STRING STRING 48 16 N Positions 2-3 specify the associated RAM number; position 1 is the record type. The associated CRASTRS entries: EN_US EN_US 00037A02101 00037A02102 COMPILE RESET EN_US 00037P02006 PARM EN_US EN_US 00037T02000 00037T02001 OK RSC Parameters Completed successfully Here positions 9-13 specify the codepage, and 14-16 the record type and RAM number. These entries 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 has Parameters as displayed text (the name PARM is not used). COMPILE has two customised return values with names OK as and RSC, respectively (the descriptions, Completed successfully for OK) are not used). CARMA Developer's Perspective ( © A. Rudd, Datev eG) 12 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 CARMA Developer's Perspective ( © A. Rudd, Datev eG) 13 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. CARMA Developer's Perspective ( © A. Rudd, Datev eG) 14 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 CARMA Developer's Perspective ( © A. Rudd, Datev eG) 15 The associated user-written performAction() 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 first parameter 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. CARMA Developer's Perspective ( © A. Rudd, Datev eG) 16 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. CARMA Developer's Perspective ( © A. Rudd, Datev eG) 17 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. CARMA Developer's Perspective ( © A. Rudd, Datev eG) 18 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. CARMA Developer's Perspective ( © A. Rudd, Datev eG) 19 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 Developer's Perspective ( © A. Rudd, Datev eG) 20 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 Developer's Perspective ( © A. Rudd, Datev eG) 21 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. CARMA Developer's Perspective ( © A. Rudd, Datev eG) 22 CRADEF Language-independent CAF data (one record for each CAF object type: A = action, P = parameter, R = RAM, T = return value) A01004 A01010 A01011 A01014 A01100 A01101 A02004 A02013 A02014 A02101 A02102 D02010 P01000 P01001 P01002 P01003 P01004 P01005 P02000 P02001 P02002 P02003 P02004 P02005 P02006 R00000 R01000 R02000 T02000 T02001 001,003! 001,002! 001,002! 000! 001,004,005! 001,004,005! 003,004! 003,004,005!000 000,001,002! 006!000,001 006!000 STRING STRING STRING STRING STRING STRING STRING STRING STRING STRING STRING STRING STRING 1.1 1.0 1.0 STRING STRING C C C 16 16 16 16 1 1 8 8 8 44 8 32 32 Z/OSV1R41.0 1.0 1.0 Z/OSV1R61.0 48 16 N N N N N N N N N N N N N CRARPDS CRARSCLM RUDDRAM CARMA Developer's Perspective ( © A. Rudd, Datev eG) 23 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 EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US EN_US 00037A01004 00037A01010 00037A01011 00037A01014 00037A01100 00037A01101 00037A02004 00037A02009 00037A02013 00037A02014 00037A02101 00037A02102 00037D02010 00037P01000 00037P01001 00037P01002 00037P01003 00037P01004 00037P01005 00037P02000 00037P02001 00037P02002 00037P02003 00037P02004 00037P02005 00037P02006 00037R00000 00037R01000 00037R02000 00037T02000 00037T02001 BUILD PROMOTE COMPILE RESET PROJECT PROJDEF ACCESS LANGUAGE SCOPE MODE PROJECT PV PGM DSN MEM OPTIONS PARM PDS RAM SCLM RAM SRCVW RAM OK RSC What is the project name? What is the project definition? Access? What is the language? N What is the scope? C What is the mode? Project name? Project version? Program name? Dataset name? Member name? Options? Parameters Allows browsing of PDSs and browsing/modification Capable of performing all CARMA API actions My test RAM; Completed successfully CARMA Developer's Perspective ( © A. Rudd, Datev eG) 24 Schematic relationship between CRADEF entries (simplified) A02014 A02101 A02102 P01000 … P02000 P02001 P02002 P02003 P02004 P02005 R00000 R01000 R02000 T02000 000,001,002! 000!000 000!000 STRING 16 N STRING STRING STRING STRING STRING STRING 1.1 1.0 1.0 STRING 8 8 8 44 8 32 Z/OSV1R41.0 1.0 1.0 Z/OSV1R61.0 2 N N N N N N CRARPDS CRARSCLM RUDDRAM C C C CARMA Developer's Perspective ( © A. Rudd, Datev eG) 25 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 CARMA Developer's Perspective ( © A. Rudd, Datev eG) 26 The associated DATEV RAM properties (from the context menu) CARMA Developer's Perspective ( © A. Rudd, Datev eG) 27 Disabled Action entry An Action entry is customised to specify the input parameters and return values. Extract from the CRADEF file. D02010 Associated CRASTRS entry: EN_US 00037D02010 CRADEF schematic ┌─┬───┬─────┐ │D│0│2│0│1│0│ └┬┴─┬─┴─────┘ │ │ └──┬──┘ │ │ │ │ │ └──────────────► Action ID to be disabled │ └───────────────────► RAM ID └──────────────────────► D = Disable The associated CRASTRS entry must only be present for completeness, although it does not contain any text. The associated action (in this case, 010 = Lock) cannot be invoked for this RAM. The associated context menu entry will be greyed-out. Example of context menu with disable action. CARMA Developer's Perspective ( © A. Rudd, Datev eG) 28 Customised Action entry An Action entry is customised to specify the input parameters and return values. Extract from the CRADEF file. A02013 P02003 P02004 P02005 003,004,005|000 STRING 44 STRING 8 STRING 32 N N N Associated CRASTRS entries: EN_US EN_US EN_US 00037P02003 00037P02004 00037P02005 DSN MEM OPTIONS Dataset name? Member name? Options? CRADEF schematic ┌─┬───┬─────┬───┬─────┬─────┬─────┬─┬─────┐ │A│0│2│0│1│3│ │0│0│3│0│0│4│0│0│5│|│0│0│0│ └┬┴─┬─┴──┬──┴───┴─────┴─────┴─────┴┬┴──┬──┘ │ │ │ └────────┬────────┘│ │ │ │ │ │ │ │ │ │ │ │ │ └───────► │ │ │ │ └───────────► │ │ │ └─────────────────────► │ │ │ │ │ └─────────────────────────────────────► │ │ │ └──────────────────────────────────────────► │ └─────────────────────────────────────────────► Return value ID (-> T record) Delimiter (note: ! in German) Parameter IDs (-> P records) Secondary ID (= Action ID) RAM ID A = Action Parameter entry ┌─┬───┬─────┬───┬──────┬──┬─┐ │P│0│2│0│0│3│ │STRING│44│N│ └┬┴─┬─┴──┬──┴───┴───┬──┴─┬┴┬┘ │ │ │ │ │ │ │ │ │ │ │ └────────► │ │ │ │ │ │ │ │ │ └──────────► │ │ │ │ │ │ │ └───────────────► │ │ │ │ │ └──────────────────────────► │ │ │ └───────────────────────────────► │ └──────────────────────────────────► N = not constant Parameter length Parameter type Parameter ID RAM ID P = Parameter Associated CRASTRS entry (for brevity, without prefixed locale (EN_US) and code page (00037) ) ┌────────┬─────────┬───────────────┐ │P02003 │ DSN │ Dataset name? │ └───┬────┴────┬────┴───────┬───────┘ │ │ │ │ │ └───────────────► Description │ │ │ └────────────────────────────► Name │ └──────────────────────────────────────► Key CARMA Developer's Perspective ( © A. Rudd, Datev eG) 29 The associated parameters prompt: CARMA Developer's Perspective ( © A. Rudd, Datev eG) 30 Custom return value entry ┌─┬───┬─────┬───┬──────┬────┐ │T│0│2│0│0│0│ │STRING│ 32 │ └┬┴─┬─┴──┬──┴───┴───┬──┴─┬──┘ │ │ │ │ │ │ │ │ │ └─────────► │ │ │ │ │ │ │ └──────────────► │ │ │ │ │ └─────────────────────────► │ │ │ └──────────────────────────────► │ └─────────────────────────────────► Maximum length Return value type Return value ID RAM ID T = Return value Associated CRASTRS entry ┌────────┬───┬────────────────────────┐ │T02000 │OK │ Completed successfully │ └───┬────┴─┬─┴──────────┬─────────────┘ │ │ │ │ │ └──────────────────► Description │ │ │ └───────────────────────────────► Name │ └──────────────────────────────────────► Key CARMA Developer's Perspective ( © A. Rudd, Datev eG) 31 The associated displayed custom return value mask: CARMA Developer's Perspective ( © A. Rudd, Datev eG) 32 Difference between a "customised action" and a "custom action" A "customised action" is a standard action (for example, checkIn) that has user-defined parameters and return values. A "custom action" is a new action that is invoked from the Custom entry in the context menu and which causes the performAction service to be called with the associated custom action ID. CARMA Developer's Perspective ( © A. Rudd, Datev eG) 33 Wrapper function Wrapper functions can be used to "wrap" existing services so they can be invoked from a RAM. The form of the wrapper function depends on the environment in which the existing service runs. Because the services (APIs, application programming interfaces) provided by SRCVW are REXX execs, the REXX interpreter must be invoked to perform the service. The wrapper function described here (execREXXProcedure()) is written as a C function that is passed the name of the REXX exec to be called. This name is passed to IRXEXEC() (the REXX interpreter) that invokes the named exec and returns the processing result as function return value. This wrapper function can be invoked as a C function. Sample wrapper function execREXXProcedure(): execute specified REXX procedure #include #include #include #include #include <stdlib.h> <string.h> <stdio.h> <stdarg.h> "REXX.h" /* REXX control block definitions */ #pragma linkage (OSFUNC,OS) typedef int OSFUNC(); #define LBUF 1024 /* maximum length of the result buffer */ #define NARG 20 /* maximum number of arguments */ #define SUBROUTINE 0x20000000 /* invoke procedure as subroutine */ EXECBLOCK execblk = {"IRXEXECB",48, 0, " *pexecblk = &execblk; ","SYSPROC "," ",NULL,0}, EVALBLOCK evalblk = { 0, LBUF/8, 0, 0 }, *pevalblk = &evalblk; ARGLIST arglist_entry[NARG+1], *parglist = arglist_entry; /* function prototypes */ #define MIN(x,y) (x < y) ? x : y char *execREXXProcedure(char *procname, int narg, ... ) { va_list argptr; OSFUNC *fptr; int rc; int p0 = 0; static char result[LBUF+1]; int n; /* execution code */ fptr = (OSFUNC *)fetch("IRXEXEC "); if (fptr == NULL) { puts("IRXEXEC fetch error"); return ""; } memset(execblk.exec_member,' ',8); n = MIN(strlen(procname),8); memcpy(execblk.exec_member,procname,n); CARMA Developer's Perspective ( © A. Rudd, Datev eG) 34 va_start(argptr, narg); /* get first argument */ for (n=0; n < narg; n++) { char *pc; pc = va_arg(argptr, char *); arglist_entry[n].argstring_ptr = pc; arglist_entry[n].argstring_length = strlen(pc); } va_end(argptr); arglist_entry[n+1].argstring_ptr = (void*)-1; arglist_entry[n+1].argstring_length = -1; rc = (*fptr)(&pexecblk,&parglist,SUBROUTINE,p0,p0,&pevalblk,p0,p0); if (rc != 0) { printf("IRXEXEC RC:%d\n",rc); return ""; } /* make returned result C-processable */ memcpy(result,evalblk.evalblock_evdata,evalblk.evalblock_evlen); result[evalblk.evalblock_evlen] = '\0'; return result; } CARMA Developer's Perspective ( © A. Rudd, Datev eG) 35 Sample legacy exec /* REXX SESVCRES – SRCVW RESET ACTION */ PARSE ARG pj, pv, pgm, pgmv /* Trap function display output */ CALL OUTTRAP 'msg.','*','NOCONCAT' "SRCVW RESET -P" pj "-PV" pv "-PGM" pgm "-PGMV" pgmv msg = '' /* Clear result string */ DO j = 1 TO msg.0 msg = msg !! msg.j END RETURN msg Associated call: presult = execREXXProcedure("SESVCRES",4,pj,pv,pgm,pgmv); The wrapper for the legacy function essentially involves invoking the SCM function (here, SRCVW RESET) with the appropriate arguments and returning the SCM function output as result string. Because the SCM function is written as a dialog function, its display output must be trapped and returned in an appropriate form. CARMA Developer's Perspective ( © A. Rudd, Datev eG) 36 Debugging The supplied sample RAM (CRARAMSA) provides the log_wrapper() logging function that writes the specified data to the host log. For WDz 6, a separate log file is created with the name: dataset name: <userid>.CRAdhhmm. The log contains information from both CARMA and the RAM. For RDz 7, the CARMA log is written to the print file DD:CARMALOG; the RAM log is written to the print file DD:SYSnnnnn (nnnnn is a running number). Sample log: T02161A.CRA00847: Initializing CARMA at Tue May0 9 08:47:40 2006 -----------------------------------------------v2.0 CARMA: Loading the RAM List CARMA: Retrieving CAF actions from CRADEF CARMA: Finished retrieving CAF actions from CRADEF CARMA: Retrieving CAF disabled actions from CRADEF CARMA: Finished retrieving CAF disabled actions from CRADEF … CARMA: Entering initRAM. Attempting to initialize 2. CARMA: Entering function: Initialize RAM CARMA: Opening the VSAM Cluster CARMA: Looking for module RUDDRAM CARMA: Attempting to run RAM function: Initialize RAM SRCVWRAM: Entering initRAM SRCVWRAM: Received trace level: 3 SRCVWRAM: Received log ptr: 1C2E2794 SRCVWRAM: Received log function ptr: 1C2DA4F8 CARMA: Returned from RAM function: Initialize RAM CARMA: Exiting function: Initialize RAM CARMA: Entering function: Get Instances CARMA: Attempting to run RAM function: Get Instances SRCVWRAM: Entering getInstances SRCVWRAM: Gathering instances SRCVWRAM: Allocating memory for instance array SRCVWRAM: Adding instances to records array SRCVWRAM: Returning instance array CARMA: Returned from RAM function: Get Instances CARMA: Exiting function: Get Instances … CARMA Developer's Perspective ( © A. Rudd, Datev eG) 37 The required level of tracing can be set online from the Connection properties (context): 0 = Error 1 = Warning 2 = Information 3 = Debug CARMA Developer's Perspective ( © A. Rudd, Datev eG) 38 The higher the level, the more information that will be logged. The supplied sample RAM (CRARAMSA) provides the log_wrapper() logging function that can be used to write the specified data to the host log. The function is called with the level to be logged (as above, -1 = no logging, 0 = error) and the data in printf format. For example log_wrapper(0, "Entering getInstances"); log_wrapper(2, "Gathering instances"); log_wrapper(3, "Received instance ID: %.128s", instanceID); CARMA Developer's Perspective ( © A. Rudd, Datev eG) 39 Errors RDz also maintains a log file (…<workspace>/.metadata/.log). This contains debugging information than may be useful for IBM for diagnostic purposes. Example !ENTRY com.ibm.carma.client 4 380 Mai 10, 2006 10:13:58.814 !MESSAGE Could not execute Get Container Contents: [380] Error from CARMA Host: 380: Response Processing Error (CARMA Content List)[line 1]: Expected 2 attributes and recieved 1 attributes. !STACK 0 com.ibm.carma.CARMAException: [380] Error from CARMA Host: 380: Response Processing Error (CARMA Content List)[line 1]: Expected 2 attributes and recieved 1 attributes. at com.ibm.carma.client.subsystem.CARMASubSystem.processErrorMessage(Unknown Source) at com.ibm.carma.client.subsystem.CARMASubSystem.processErrorStatus(Unknown Source) at com.ibm.carma.client.subsystem.CARMASubSystem.executeCommand(Unknown Source) at com.ibm.carma.client.transport.datastore.DataStoreCommandExecutor.executeCommand(Unknown Source) at com.ibm.carma.client.transport.datastore.DataStoreCommandExecutor.executeCommand(Unknown Source) at com.ibm.carma.client.transport.datastore.DatastoreRepositoryTransport.findContainerContents(Unknown Source) at com.ibm.carma.model.impl.ResourceContainerHelper.refresh(Unknown Source) at com.ibm.carma.model.impl.CARMAContainerImpl.refresh(Unknown Source) at com.ibm.carma.model.impl.ResourceContainerHelper.refresh(Unknown Source) at com.ibm.carma.model.impl.ResourceContainerImpl.refresh(Unknown Source) at com.ibm.carma.ui.job.RefreshJob.run(Unknown Source) at org.eclipse.core.internal.jobs.Worker.run(Unknown Source) CARMA Developer's Perspective ( © A. Rudd, Datev eG) 40 Summary A few personal suggestions for RAM development 1. Start simple. 2. Until you are sure of what you are doing, supply trace information (log function, displays). 3. Do not make any errors -> a RAM failure will close the connection to a CARMA (the CRASUBMT job). Current CARMA restrictions 1. A new member cannot be added to the SCM from CARMA. Although a check-in can be implemented, there is no direct reference to the associated program entry; this means all program-related data must be entered. One work-around is to create a Menu Manager entry (this is described in a subsequent paper). 2. A checked-out member exists only as a local file. 3. Limited integration with other RDz functionality, such as compile. For example, it is not possible to compile directly a CARMA repository program. More correctly, it is not possible to use existing properties. 4. When an extract for a "container" is performed, all members will be copied to the local CARMA project. In our case, this can be very many members and so is not practicable. 12.08.2009 CARMA Developer's Perspective ( © A. Rudd, Datev eG) 41 12.08.2009 November 14th ©DATEV eG; alle Rechte vorbehalten 2008 Mainframe Neuheiten CARMA Developer's Perspective ( © A. Rudd, Datev eG) 2 42