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.

The DFH$W2S1 sample service routine performs the following tasks:
  • 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.