DFH$W2S1 C sample service routine for Atom feeds
The sample service routine DFH$W2S1 is a skeleton program in C language that shows you how to read the parameters in the DFHATOMPARMS container, update the metadata and content containers (such as DFHATOMTITLE and DFHATOMCONTENT), and update and return the DFHATOMPARMS container.
If you create and install an appropriate RDO definition, which must specify EXECKEY(CICS), for DFH$W2S1, you can run the sample service routine to supply some data for test purposes in response to GET requests for an Atom feed. As shipped, the program returns only the default data that is set up by its code, and it does not handle POST, PUT, or DELETE requests. The process of identifying the required record from the resource that holds the data for your Atom entries, and extracting the appropriate fields from the record, or updating the record in response to a POST, PUT, or DELETE request, is specific to your choice of resource and the structure of the records in that resource. For an example of how your service routine can interact with your resource, see the description of DFH0W2F1 in DFH0W2F1 - COBOL sample service routine for Atom feeds. DFH0W2F1 interacts with the CICS® sample file FILEA.
- Includes the C header file for the copybook DFHW2APH that contains the parameter list for DFHATOMPARMS, and the copybook DFHW2CNH that contains the constants for the response codes.
- Defines a structure called "outdata" that will be placed in the
temporary work area (TWA). The program will use this structure to
store new data for the DFHATOMPARMS parameters, and will return pointers
to the new data for CICS to replace the existing values of the parameters.
The storage for your new data for the DFHATOMPARMS parameters must
be in the TWA so that it can be read by CICS Atom processing.
typedef struct { char atomid??(50??); char published??(30??); ... char selector??(20??); } outdata;
- Defines a structure called "indata", which is a placeholder that
shows you how to extract all the values from the DFHATOMPARMS parameters.
In practice, your service routine can extract the values as it needs
them to perform each processing step.
typedef struct { char* resname; char* restype; char* atomtype; ... char* emailfld; } indata;
- Provides a helper method getParameter that you can use to obtain
the pointer and length information from a parameter in DFHATOMPARMS,
read the value of the parameter into memory, add a null terminator
(zero byte) so that it can be used as a C string, and return a pointer
to the new memory location.
char* getParameter(atmp_parameter* ParamPtr) { char* DataPtr; int DataLen; DataLen = ParamPtr->atmp_parameter_len; EXEC CICS GETMAIN SET(DataPtr) FLENGTH(DataLen+1) INITIMG(0x00); if (DataLen != 0) { memcpy(DataPtr, ParamPtr->atmp_parameter_ptr, DataLen); } return DataPtr; }
- Provides a helper method updatedAtomParam that you can use to
update the pointer and length that CICS sent for a DFHATOMPARMS parameter
with a pointer to a new string value containing your new data, and
the length of that string.
void updatedAtomParam(char *value, atmp_parameter *ParamPtr) { ParamPtr->atmp_parameter_ptr = (unsigned long*)value; ParamPtr->atmp_parameter_len = strlen(value); }
- Provides a helper method updateAtomContainer that uses the EXEC
CICS PUT CONTAINER command to update one of the metadata and content
containers (such as DFHATOMTITLE and DFHATOMCONTENT) with data for
your Atom entry, taken from a field in the record in the resource
that holds the data for your Atom entries, and set the corresponding
option bit to which DFHATOMPARMS supplied a pointer.
void updateAtomContainer(char *cName, char *cChannel, char *value, atmp_options_bits *optPtr) { int len = strlen(value); EXEC CICS PUT CONTAINER(cName) CHANNEL(cChannel) FROM(value) FLENGTH(len) FROMCODEPAGE("IBM037"); /* work out which option to set */ if (strcmp(cName, "DFHATOMTITLE ") == 0) { (*optPtr).atmp_options_outbit.atmp_outopt_byte1.opttitle = 1; } else if (strcmp(cName, "DFHATOMSUMMARY ") == 0) { (*optPtr).atmp_options_outbit.atmp_outopt_byte1.optsumma = 1; } else if (strcmp(cName, "DFHATOMCATEGORY ") == 0) { (*optPtr).atmp_options_outbit.atmp_outopt_byte1.optcateg = 1; } else if (strcmp(cName, "DFHATOMAUTHOR ") == 0) { (*optPtr).atmp_options_outbit.atmp_outopt_byte1.optauthor = 1; } else if (strcmp(cName, "DFHATOMAUTHORURI ") == 0) { (*optPtr).atmp_options_outbit.atmp_outopt_byte1.optautheml = 1; } else if (strcmp(cName, "DFHATOMEMAIL ") == 0) { (*optPtr).atmp_options_outbit.atmp_outopt_byte1.optauthuri = 1; } }
- In the main program, sets up variables such as the storage for data that will be placed into the metadata and content containers (such as DFHATOMTITLE and DFHATOMCONTENT), and the "outdata" and "indata" structures.
- Issues an EXEC CICS ADDRESS TWA command to set up storage for
the "outdata" structure in the TWA, and populates this structure with
default values. These default values are returned if you run the sample
service routine as supplied. By setting the value for the ATMP_NEXTSEL parameter
to 0, the sample service routine makes CICS request the same Atom
entry, consisting of this default data, over and over until the number
of entries specified as the window for the Atom feed document are
obtained. When you code your own service routine that supplies real
data, do not use default values, because depending on the request
method, you might want to leave a number of data items unchanged.
EXEC CICS ADDRESS TWA(outData); strcpy(outData->atomid, "cics-atomservice-sample:2009-02-02T00:00:00Z"); strcpy(outData->published, "2009-02-02T00:00:00Z"); strcpy(outData->updated, "2009-02-20T14:54:34Z"); strcpy(outData->edited, "2009-02-20T14:54:34Z"); strcpy(outData->etagval, ""); strcpy(outData->selector, ""); strcpy(outData->nextsel, "0"); strcpy(outData->prevsel, ""); strcpy(outData->firstsel, ""); strcpy(outData->lastsel, "");
- Issues EXEC CICS GETMAIN commands to obtain storage to hold the
values of the metadata and content containers (such as DFHATOMTITLE
and DFHATOMCONTENT), and populates these containers with default data.
The data in the containers does not need to be in the TWA. The content
for the Atom entry, in the DFHATOMCONTENT container, must be enclosed
in <atom:content> opening and closing tags, that may specify a
type attribute giving the type of content. You may abbreviate <atom:content>
to just <content>, as the sample service routine does.
EXEC CICS GETMAIN SET(AtomContent) FLENGTH(512) INITIMG(0x00); EXEC CICS GETMAIN SET(AtomTitle) FLENGTH(50) INITIMG(0x00); EXEC CICS GETMAIN SET(AtomSummary) FLENGTH(100) INITIMG(0x00); EXEC CICS GETMAIN SET(AtomCategory) FLENGTH(30) INITIMG(0x00); EXEC CICS GETMAIN SET(AtomAuthor) FLENGTH(40) INITIMG(0x00); EXEC CICS GETMAIN SET(AtomAuthorUri) FLENGTH(256) INITIMG(0x00); EXEC CICS GETMAIN SET(AtomEmail) FLENGTH(256) INITIMG(0x00); strcpy(AtomContent, "<content type='text/xml'>Hello world</content>"); strcpy(AtomTitle, "Sample Service Routine Entry"); strcpy(AtomSummary, "This is an entry from the sample service routine"); strcpy(AtomCategory, "sample-entry"); strcpy(AtomAuthor, "CICS Sample service routine"); strcpy(AtomAuthorUri, ""); strcpy(AtomEmail, "");
- Issues an EXEC CICS ASSIGN CHANNEL command to get the name of
the current channel for use on the later GET and PUT CONTAINER commands.
EXEC CICS ASSIGN CHANNEL(cChannel);
- Checks for the presence of the DFHREQUEST container, which CICS
uses to pass the body of a web client's POST or PUT request to the
service routine. The first EXEC CICS GET CONTAINER command requests
the length of the container, and if a nonzero response code is returned,
meaning that either the container does not exist or there is some
problem with it, does not proceed. If a request body has been passed,
the sample service routine reads its contents into storage.
EXEC CICS GET CONTAINER("DFHREQUEST ") CHANNEL(cChannel) NODATA FLENGTH(DataLen) RESP(Resp) RESP2(Resp2); if(Resp != 0 || Resp2 != 0) { DataLen = -1; } /* If we have a request body then get it */ if(DataLen != -1) { DataLen++; EXEC CICS GETMAIN SET(RequestBody) FLENGTH(DataLen) INITIMG(0x00); EXEC CICS GET CONTAINER("DFHREQUEST ") INTO(RequestBody) FLENGTH(DataLen); }
- Issues an EXEC CICS GET CONTAINER command to set a pointer ParamList
to the beginning of the data for the DFHATOMPARMS parameters.
EXEC CICS GET CONTAINER("DFHATOMPARMS ") SET(ParamListData) FLENGTH(DataLen); ParamList = (atmp_parameter_list*)ParamListData;
- Goes through the data for the DFHATOMPARMS parameters, and uses
the helper method getParameter to obtain the value of each parameter
and set a pointer for it in the "inData" structure.
optPtr = (atmp_options_bits*)ParamList->atmp_options; ParamPtr = (atmp_parameter*)ParamList->atmp_resname; inData.resname = getParameter(ParamPtr); ParamPtr = (atmp_parameter*)ParamList->atmp_restype; inData.restype = getParameter(ParamPtr); ... ParamPtr = (atmp_parameter*)ParamList->atmp_email_fld; inData.emailfld = getParameter(ParamPtr);
- Indicates where you must provide code that interacts with the resource that holds the data for your Atom entries, based on the information in the DFHATOMPARMS parameters and the DFHREQUEST container. Your service routine needs to locate the required record in the resource and extract the appropriate fields from the record in response to a GET request, or update the record in response to a POST, PUT, or DELETE request. The value of the ATMP_HTTPMETH parameter tells your service routine what the request method is.
- Shows you how to place the data that you have obtained from your
resource record into the memory locations indicated by the pointers
in the outData structure, and into the storage for the metadata and
content containers (such as DFHATOMTITLE and DFHATOMCONTENT). The
example shows you how to add a selector value for the current record
if the ATMP_SELECTOR parameter was null on input
for the service routine.
* strcpy(outData->atomid, "....."); * strcpy(outData->published, "....."); * strcpy(outData->updated, "....."); * strcpy(outData->edited, "....."); * strcpy(outData->etagval, "....."); * strcpy(outData->nextsel, "....."); * strcpy(outData->prevsel, "....."); * strcpy(outData->firstsel, "....."); * strcpy(outData->lastsel, "....."); * * if (strlen(inData->selector) == 0) { * strcpy(outData->selector, "....."); * } * * strcpy(AtomContent, "...."); * strcpy(AtomTitle, "...."); * strcpy(AtomSummary, "...."); * strcpy(AtomCategory, "...."); * strcpy(AtomAuthor, "...."); * strcpy(AtomAuthorUri, "...."); * strcpy(AtomEmail, "....");
- Uses the updatedAtomParam helper method to update the storage
for each DFHATOMPARMS parameter with the pointers and lengths for
your new items of data.
updatedAtomParam(outData->atomid, (atmp_parameter*)ParamList->atmp_atomid); updatedAtomParam(outData->published, (atmp_parameter*)ParamList->atmp_published); updatedAtomParam(outData->updated, (atmp_parameter*)ParamList->atmp_updated); updatedAtomParam(outData->edited, (atmp_parameter*)ParamList->atmp_edited); updatedAtomParam(outData->etagval, (atmp_parameter*)ParamList->atmp_etagval); updatedAtomParam(outData->nextsel, (atmp_parameter*)ParamList->atmp_nextsel); updatedAtomParam(outData->prevsel, (atmp_parameter*)ParamList->atmp_prevsel); updatedAtomParam(outData->firstsel, (atmp_parameter*)ParamList->atmp_firstsel); updatedAtomParam(outData->lastsel, (atmp_parameter*)ParamList->atmp_lastsel); if (strlen(outData->selector) != 0) { updatedAtomParam(outData->selector, (atmp_parameter*)ParamList->atmp_selector); }
- Uses the updateAtomContainer helper method to add your new data
to the metadata and content containers, and set the option bit to
indicate the presence of each container.
updateAtomContainer("DFHATOMTITLE ",cChannel,AtomTitle,optPtr); updateAtomContainer("DFHATOMSUMMARY ",cChannel,AtomSummary,optPtr); updateAtomContainer("DFHATOMCATEGORY ",cChannel,AtomCategory,optPtr); updateAtomContainer("DFHATOMAUTHOR ",cChannel,AtomAuthor,optPtr); updateAtomContainer("DFHATOMAUTHORURI",cChannel,AtomAuthorUri,optPtr); updateAtomContainer("DFHATOMEMAIL ",cChannel,AtomEmail,optPtr); updateAtomContainer("DFHATOMCONTENT ",cChannel,AtomContent,optPtr);
- Provides a response code from the selection defined in the DFHW2CNH
copybook. The reason code is ignored by CICS at present and reserved
for future use, so its content is arbitrary.
ResponsePtr = (atmp_responses*)ParamList->atmp_response; ResponsePtr->atmp_response_code = ATMP_RESP_NORMAL; /* * ResponsePtr->atmp_response_code = ATMP_RESP_NOT_FOUND; * ResponsePtr->atmp_response_code = ATMP_RESP_NOT_AUTH; * ResponsePtr->atmp_response_code = ATMP_RESP_DISABLED; * ResponsePtr->atmp_response_code = ATMP_RESP_ALREADY_EXISTS; * ResponsePtr->atmp_response_code = ATMP_RESP_ACCESS_ERROR; */ ResponsePtr->atmp_reason_code = 0;
- Returns control to CICS automatically as the main program ends. CICS Atom processing uses the data from the metadata and content containers, and the data in the TWA for the DFHATOMPARMS parameters for which the service routine has supplied new pointers and lengths, to construct the Atom entry. CICS then requests further Atom entries from the service routine in the same way, until the window of entries to construct the Atom feed document is complete.