如何从 iSeries COBOL 调用 Web 服务?

发布于 2024-12-21 21:56:09 字数 3823 浏览 3 评论 0原文

我们需要能够从 iSeries LPAR (V6R1) 上运行的 COBOL 代码调用内部 Web 服务。我完成了一个完整的示例,可以在此处找到。因此,我的下一步是尝试重复该过程并调用我们现有的 Web 服务之一。

我使用 QSH 中的 WSDL2WS 命令​​来生成 C 客户端存根。我修改了示例 COBOL 客户端程序并尝试调用我的 Web 服务。我遇到的问题似乎与示例 C 客户端方法返回指针而 COBOL 代码将它们分配给指针这一事实有关。我怀疑 COBOL 代码中的错误是问题的根源,因为 WSDL2WS 为我的 Web 服务方法创建的 C 方法返回一个简单的 xsdc_string 而不是指向自定义结果类型的指针:

xsdc__string TestUnsuccessfulMessage(AXISCHANDLE stub)
{
    AXISCHANDLE call = axiscStubGetCall(stub);
    xsdc__string Ret = NULL;

    axiscCallSetSoapFaultNamespace(call, "http://myserver/PSItemMaintenance/ItemMaintenanceService.svc");


    // ======================================================================
    // Initialize client engine, set SOAP version, SOAPAction, operation, etc.
    // ======================================================================

    if (AXISC_SUCCESS != axiscCallInitialize(call, C_DOC_PROVIDER ))
        return Ret;

    if (NULL==axiscCallGetTransportProperty(call,"SOAPAction",0))
        axiscCallSetTransportProperty(call,AXISC_SOAPACTION_HEADER , "http://tempuri.org/IItemMaintenanceService/TestUnsuccessfulMessage");

    axiscCallSetSOAPVersion(call, SOAP_VER_1_1);
    axiscCallSetOperation(call, "TestUnsuccessfulMessage", "http://tempuri.org/");

    // ======================================================================
    // Apply SSL configuration properties and user-set SOAP headers.
    // ======================================================================

    axiscStubIncludeSecure(stub);
    axiscStubApplyUserPreferences(stub);


    // ======================================================================
    // Invoke web service, send/receive operation. Handle output parameters, if any.
    // ======================================================================

    if (AXISC_SUCCESS == axiscCallSendAndReceive(call))
    {
        if(AXISC_SUCCESS == axiscCallValidateMessage(call, "TestUnsuccessfulMessageResponse", "http://tempuri.org/", true_))
        {
            Ret = axiscCallGetElementAsString(call, "TestUnsuccessfulMessageResult", 0);
        }

        axiscStubCheckForExtraneousElements(stub);
    }
    axiscCallUnInitialize(call);
    return Ret;
}

我可以在调试中设置 Web 服务模式,当我运行调用 COBOL 和 C 模块的程序时,可以看到来自 iSeries 的调用。我还可以看到我返回了一个简单的字符串值。

当 COBOL 程序尝试获取返回值并使用它时,就会出现问题。我相信 COBOL 代码的相关位是:

LINKAGE PROCEDURE FOR "TestSuccessfulMessage"
                 USING ALL DESCRIBED    

LINKAGE SECTION.                     
 01 LookupResult         PIC X(1000).  

CALL PROCEDURE "TestSuccessfulMessage"
 USING BY VALUE STUB              
 RETURNING LookupResult.          

当以这种方式编码时,我得到了 MCH3601。如果我返回一个指针,然后将地址设置为 LookupResult,我最终会得到一个空值。

我希望我只是在某个地方遗漏了一个小细节。我的 COBOL 经验很少。我只是想创建一个参考应用程序作为我们公司内另一个团队的概念证明。任何帮助或建议尝试什么将不胜感激。我可以提供更多代码。

更新:我尝试将 LookupResult 声明移至工作存储中。虽然这消除了 MCH3601 错误,但我的显示屏中却出现了一堆垃圾数据。我可以在数据中看到有关我的 iSeries 会话的信息(即 deviceID 等)。

我还尝试将 LookupResult 保留在链接部分中,并在工作存储中创建一个指针。然后我添加了“SET Address of LookupResult TO ResultPointer”。同样,调用结束时没有错误,但是当我显示 LookupResult 时,我得到了垃圾数据。但是,它与直接返回 LookupResult 时返回的数据不同。我可以在该数据中看到 SOAP 信封的各个部分。

最终: 我必须进行的所有更改都在 COBOL 代码中。以下是相关部分:

WORKING-STORAGE SECTION.              
01 Endpoint             PIC X(100).   
01 STUB                 USAGE POINTER.
01 ResultPointer        USAGE POINTER.

LINKAGE SECTION.                      
01 pszEndpoint          PIC X(100).   
01 LookupResult         PIC X(7).   

CALL PROCEDURE "TestSuccessfulMessage"       
     USING BY VALUE STUB                     
     RETURNING INTO ResultPointer.           

SET Address of LookupResult TO ResultPointer.

We need to be able to call an internal web service from COBOL code running on an iSeries LPAR (V6R1). I worked through the one complete example that I was able to find online here. So, my next step was to try to repeat the process and call one of our existing web services.

I used the WSDL2WS command from QSH to generate the C client stubs. I modified the example COBOL client program and attempted a call to my web service. The problem that I'm running into seems to be related to the fact that the example C client methods are returning pointers and the COBOL code is assigning them to pointers. I suspect that an error in my COBOL code is the root of my problem, because the C method that that WSDL2WS created for my web service method returns a simple xsdc_string not a pointer to a custom result type:

xsdc__string TestUnsuccessfulMessage(AXISCHANDLE stub)
{
    AXISCHANDLE call = axiscStubGetCall(stub);
    xsdc__string Ret = NULL;

    axiscCallSetSoapFaultNamespace(call, "http://myserver/PSItemMaintenance/ItemMaintenanceService.svc");


    // ======================================================================
    // Initialize client engine, set SOAP version, SOAPAction, operation, etc.
    // ======================================================================

    if (AXISC_SUCCESS != axiscCallInitialize(call, C_DOC_PROVIDER ))
        return Ret;

    if (NULL==axiscCallGetTransportProperty(call,"SOAPAction",0))
        axiscCallSetTransportProperty(call,AXISC_SOAPACTION_HEADER , "http://tempuri.org/IItemMaintenanceService/TestUnsuccessfulMessage");

    axiscCallSetSOAPVersion(call, SOAP_VER_1_1);
    axiscCallSetOperation(call, "TestUnsuccessfulMessage", "http://tempuri.org/");

    // ======================================================================
    // Apply SSL configuration properties and user-set SOAP headers.
    // ======================================================================

    axiscStubIncludeSecure(stub);
    axiscStubApplyUserPreferences(stub);


    // ======================================================================
    // Invoke web service, send/receive operation. Handle output parameters, if any.
    // ======================================================================

    if (AXISC_SUCCESS == axiscCallSendAndReceive(call))
    {
        if(AXISC_SUCCESS == axiscCallValidateMessage(call, "TestUnsuccessfulMessageResponse", "http://tempuri.org/", true_))
        {
            Ret = axiscCallGetElementAsString(call, "TestUnsuccessfulMessageResult", 0);
        }

        axiscStubCheckForExtraneousElements(stub);
    }
    axiscCallUnInitialize(call);
    return Ret;
}

I can setup the web service in debug mode and can see the call from the iSeries when I run the program that calls the COBOL and C modules. I can also see that I'm returning back a simple string value.

The problem comes when the COBOL program tries to take the return value and use it. I believe that the relevant bits of the COBOL code are:

LINKAGE PROCEDURE FOR "TestSuccessfulMessage"
                 USING ALL DESCRIBED    

LINKAGE SECTION.                     
 01 LookupResult         PIC X(1000).  

CALL PROCEDURE "TestSuccessfulMessage"
 USING BY VALUE STUB              
 RETURNING LookupResult.          

I get a MCH3601 when it's coded this way. If I return into a pointer and then set the address to LookupResult, I end up with a null value.

I hope that I'm just missing a small detail somewhere. I have very little COBOL experience. I'm just trying to create a reference app as a proof of concept for another team within our company. Any help, or suggestions of what to try would be appreciated. I can supply more code.

Update: I tried just moving the LookupResult declaration into working storage. While that eliminated the MCH3601 error, I just got a bunch of garbage data in my display. I can see pieces of info about my iSeries session (i.e. deviceID, etc...) within the data.

I also tried leaving the LookupResult in the linkage section and creating a pointer in working storage. Then I added a "SET Address of LookupResult TO ResultPointer". Again, the call ended without error, but when I display LookupResult I get garbage data. However, it's different than the data that comes back if I return straight into LookupResult. I can see pieces of the SOAP envelope in this data.

Final:
All of the changes that I had to make were in the COBOL code. Here are the relevant pieces:

WORKING-STORAGE SECTION.              
01 Endpoint             PIC X(100).   
01 STUB                 USAGE POINTER.
01 ResultPointer        USAGE POINTER.

LINKAGE SECTION.                      
01 pszEndpoint          PIC X(100).   
01 LookupResult         PIC X(7).   

CALL PROCEDURE "TestSuccessfulMessage"       
     USING BY VALUE STUB                     
     RETURNING INTO ResultPointer.           

SET Address of LookupResult TO ResultPointer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

葵雨 2024-12-28 21:56:09

如果我返回一个指针,然后将地址设置为 LookupResult,我
最终得到一个空值。

我是一个 COBOL 人,但不是 iSeries 人。买者自负。

如果 xsdc__string 解析为指针,那么您的 COBOL 代码应该为 CALL 的 RETURNING 部分提供一个 POINTER 类型的变量。也许 C 函数实际上返回 NULL,代码当然允许它 - 也许 axiscCallInitialize 没有返回 AXISC_SUCCESS。

至少在 z/OS 上,您希望 COBOL 指针变量位于工作存储或本地存储中,然后您将 SET ADDRESS OF LookupResult TO 该指针变量。我认为这不会仅仅因为您使用不同的机器架构而改变。

...FWIW

If I return into a pointer and then set the address to LookupResult, I
end up with a null value.

I am a COBOL person, but not on iSeries. Caveat emptor.

If xsdc__string resolves to a pointer, then your COBOL code should have a variable of type POINTER for the RETURNING portion of the CALL. Perhaps the C function is in fact returning NULL, the code certainly allows for it - maybe axiscCallInitialize isn't returning AXISC_SUCCESS.

At least on z/OS, you would want the COBOL pointer variable to be in either Working-Storage or Local Storage, and then you would SET ADDRESS OF LookupResult TO that pointer variable. I'm presuming that doesn't change just because you're on a different machine architecture.

...FWIW

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文