Atom 订阅源的 DFH$W2S1 C 样本服务例程

样本服务例程 DFH$W2S1 是用 C 语言编写的框架程序,该程序显示了如何读取 DFHATOMPARMS 容器中的参数、更新元数据和内容容器(例如,DFHATOMTITLE 和 DFHATOMCONTENT)以及更新并返回 DFHATOMPARMS 容器。

如果您创建并安装相应的 RDO 定义 (必须指定针对 DFH$W2S1的 EXECKEY (CICS®)) ,那么可以运行样本服务例程来提供一些数据以用于测试目的,以响应针对 Atom 订阅源的 GET 请求。 正如已经发布的,该程序仅会返回使用其代码设置的缺省数据,而不会处理 POST、PUT 或 DELETE 请求。 从保存 Atom 条目数据的资源识别所需的记录、以及从该记录抽取适当字段、或更新该记录以对 POST、PUT 或 DELETE 请求做出响应的过程是专门针对您选择的资源以及该资源中的记录结构的。 有关服务例程如何与资源交互的示例,请参阅 DFH0W2F1 中 DFH0W2F1 的描述-针对 Atom 订阅源的 COBOL 样本服务例程。 DFH0W2F1 与 CICS 样本文件 FILEA 交互。

DFH$W2S1 样本服务例程执行以下任务:
  • 包含具有 DFHATOMPARMS 参数列表的副本 DFHW2APH 以及具有响应代码常量的副本 DFHW2CNH 的 C 头文件。
  • 定义将放入临时工作区(TWA)的称为“outdata”的结构。 该程序会使用此结构存储 DFHATOMPARMS 参数的新数据,并会返回指向该新数据的指针,以便 CICS 替换该参数的现有值。 存储 DFHATOMPARMS 参数新数据的存储器必须位于 TWA 中,以便 CICS Atom 处理过程可以读取这些数据。
    typedef struct
    {
        char atomid??(50??);
        char published??(30??);
        ...
        char selector??(20??);
    } outdata;
  • 定义称为“indata”的结构,该结构是一个占位符,显示如何从 DFHATOMPARMS 参数抽取所有值。 实际上,服务例程可以抽取这些值,因为它需要这些值来执行每个处理步骤。
    typedef struct
    {
        char* resname;  
        char* restype;
        char* atomtype;
        ...
        char* emailfld;
    } indata;
  • 提供一个帮助程序方法 getParameter,用于从 DFHATOMPARMS 的参数中获取指针和长度信息、读取内存中参数的值、添加 NULL 终止符(零字节)以便用作 C 字符串以及返回指向新内存位置的指针。
    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;
    }
  • 提供一个帮助程序方法 updatedAtomParam,您可以通过使用该方法,利用指向包含新数据的新字符串值的指针和该字符串的长度来更新 CICS 所发送的 DFHATOMPARMS 参数的指针和长度。
    void updatedAtomParam(char *value, atmp_parameter *ParamPtr)
    {
        ParamPtr->atmp_parameter_ptr = (unsigned long*)value;
        ParamPtr->atmp_parameter_len = strlen(value);
    }
  • 提供一个帮助程序方法 updateAtomContainer,此方法使用 EXEC CICS PUT CONTAINER 命令并用 Atom 条目数据(这些数据来自保存 Atom 条目数据的资源记录中的某个字段)来更新某个元数据和内容容器(例如,DFHATOMTITLE 和 DFHATOMCONTENT),并且还会对 DFHATOMPARMS 提供指针的相应选项位进行设置。
    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;
        }
        
    }
  • 在主程序中,设置变量(例如,存储将放入元数据和内容容器(如 DFHATOMTITLE 和 DFHATOMCONTENT )的数据的存储器),以及“outdata”和“indata”结构。
  • 发送 EXEC CICS ADDRESS TWA 命令,以设置 TWA 中存储“outdata”结构的存储器,并用缺省值填充该结构。 在您运行所提供的样本服务例程时,会返回这些缺省值。 通过将 ATMP_NEXTSEL 参数的值设置为 O,样本服务例程会使 CICS 不断请求相同的 Atom 条目(由缺省数据组成),直到获得 Atom 订阅源文档的窗口指定的条目数。 当您对提供实际数据的服务例程进行编码时,请勿使用缺省值,因为根据请求方法的不同,您可能希望大部分数据项保持不变。
     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, ""); 
  • 发送 EXEC CICS GETMAIN 命令,以获取包含元数据和内容容器(例如,DFHATOMTITLE 和 DFHATOMCONTENT)值的存储器,并用缺省数据填充这些容器。 这些容器中的数据不需要位于 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,     "");
  • 发送 EXEC CICS ASSIGN CHANNEL 命令,以获取当前通道的名称,供后续 GET 和 PUT CONTAINER 命令使用。
        EXEC CICS ASSIGN CHANNEL(cChannel);
  • 检查 DFHREQUEST 容器是否存在,CICS 使用该容器将 Web 客户机的 POST 或 PUT 请求的主体传递给服务例程。 第一个 EXEC CICS GET CONTAINER 命令请求容器的长度,如果返回非零响应代码(表示容器不存在或者存在某些问题),将中断请求。 如果请求主体已通过,那么样本服务例程将读取其存储器中的内容。
        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);
        }
  • 发送 EXEC CICS GET CONTAINER 命令,以将指针 ParamList 设置到 DFHATOMPARMS 参数的数据起始点。
        EXEC CICS GET CONTAINER("DFHATOMPARMS    ")
                      SET(ParamListData)
                      FLENGTH(DataLen);
        
        ParamList = (atmp_parameter_list*)ParamListData;
  • 浏览 DFHATOMPARMS 参数的数据,使用帮助程序方法 getParameter 来获取每个参数的值,并在“inData”结构中为参数设置指针。
        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);
  • 根据 DFHATOMPARMS 参数和 DFHREQUEST 容器中的信息,指明您必须提供与保存 Atom 条目数据的资源进行交互的代码的位置。 服务例程需要在资源中找到所需的记录,并从该记录抽取中适当的字段以响应 GET 请求,或者更新记录以响应 POST、PUT 或 DELETE 请求。 ATMP_HTTPMETH 参数的值向服务例程告知所用的请求方法。
  • 显示如何将从资源记录中获取的数据放到 outData 结构中指针指向的内存位置中以及元数据和内容容器(例如,DFHATOMTITLE 和 DFHATOMCONTENT)的存储器中。 该示例显示了当 服务例程的输入中 ATMP_SELECTOR 参数为 null时,如何为当前记录添加选择器值。
         *  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,     "....");
  • 使用 updatedAtomParam 帮助程序方法并用新数据项的指针和长度更新每个 DFHATOMPARMS 参数的存储器。
        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);
        }
  • 使用 updateAtomContainer 帮助程序方法,将新数据添加到元数据和内容容器中,并设置选项位以表明每个容器是否存在。
      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);
  • 从 DFHW2CNH 副本定义的选择中提供响应代码。 由于当前原因码被 CICS 忽略并留做以后使用,因此其内容是随意的。
        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;
  • 当主程序结束时,会自动将控制权返回给 CICS。 CICS Atom 处理过程使用元数据和内容容器中的数据以及 TWA 中 DFHATOMPARMS 参数(服务例程为其提供了新指针和长度)的数据来构造 Atom 条目。 然后,CICS 会以同样的方式请求服务例程中的其他 Atom 条目,直到构造 Atom 订阅源文档的条目窗口完成为止。