2011-12-19 25 views
5

Necesitamos poder llamar a un servicio web interno desde el código COBOL que se ejecuta en un iSeries LPAR (V6R1). Trabajé con el único ejemplo completo que pude encontrar en línea here. Entonces, mi próximo paso fue intentar repetir el proceso y llamar a uno de nuestros servicios web existentes.¿Cómo llamo a un servicio web de iSeries COBOL?

Utilicé el comando WSDL2WS de QSH para generar los talones del cliente C. Modifiqué el programa cliente de ejemplo COBOL e intenté llamar a mi servicio web. El problema con el que me estoy encontrando parece estar relacionado con el hecho de que los métodos del cliente C de ejemplo son punteros devueltos y el código COBOL los está asignando a los punteros. Sospecho que un error en mi código COBOL es la raíz de mi problema, ya que el método C que esa WSDL2WS creados por mi método de servicio Web devuelve un xsdc_string simple no un puntero a un tipo de resultado personalizado:

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 puede configurar el servicio web en modo de depuración y puede ver la llamada desde el iSeries cuando ejecuto el programa que llama a los módulos COBOL y C. También puedo ver que estoy devolviendo un valor de cadena simple.

El problema surge cuando el programa COBOL intenta tomar el valor de retorno y usarlo. Creo que los bits correspondientes del código COBOL son:

LINKAGE PROCEDURE FOR "TestSuccessfulMessage" 
       USING ALL DESCRIBED  

LINKAGE SECTION.      
01 LookupResult   PIC X(1000). 

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

consigo un MCH3601 cuando está codificado de esta manera. Si regreso a un puntero y luego establezco la dirección en LookupResult, termino con un valor nulo.

Espero que me falte un pequeño detalle en alguna parte. Tengo muy poca experiencia en COBOL. Solo intento crear una aplicación de referencia como prueba de concepto para otro equipo dentro de nuestra compañía. Cualquier ayuda o sugerencia de qué probar sería apreciada. Puedo suministrar más código.

Actualización: Intenté simplemente mover la declaración LookupResult al almacenamiento en funcionamiento. Si bien eso eliminó el error MCH3601, acabo de obtener un montón de datos basura en mi pantalla. Puedo ver fragmentos de información sobre mi sesión de iSeries (por ejemplo, ID de dispositivo, etc.) dentro de los datos.

También intenté dejar LookupResult en la sección de enlace y crear un puntero en el almacenamiento de trabajo. Luego agregué un "SET Address of LookupResult TO ResultPointer". Una vez más, la llamada finalizó sin error, pero cuando muestro LookupResult obtengo datos basura. Sin embargo, es diferente de los datos que se devuelven si regreso directamente a LookupResult. Puedo ver fragmentos del sobre SOAP en esta información.

Final: Todos los cambios que tuve que hacer estaban en el código COBOL. Estas son las piezas relevantes:

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. 

Respuesta

4

Si vuelvo en un puntero y después fijar la dirección a LookupResult, me terminar con un valor nulo.

Soy una persona COBOL, pero no en iSeries. Caveat Emptor.

Si xsdc__string se resuelve en un puntero, su código COBOL debe tener una variable de tipo POINTER para la parte RETORNO de CALL. Quizás la función C de hecho está devolviendo NULL, el código ciertamente lo permite, tal vez axiscCallInitialize no está devolviendo AXISC_SUCCESS.

Al menos en z/OS, desea que la variable de puntero COBOL esté en Almacenamiento de trabajo o Almacenamiento local, y luego DEBERÍA ESTABLECER LA DIRECCIÓN DE LookupResult TO esa variable de puntero. Supongo que eso no cambia solo porque estás en una arquitectura de máquina diferente.

... FWIW

+0

Gracias. Traté de usar un puntero y el comando SET ADDRESS OF también, pero en ese momento creo que mi declaración de puntero estaba en la sección de vinculación. Trataré de moverlo al almacenamiento de trabajo. También entré en el código C en modo de depuración. Puedo ver que Ret comienza como NULL, pero después de la llamada tiene un valor, que en el depurador de iSeries se muestra como Ret = SPP: DA1A1DDC05014450. –

+1

Estoy considerando esta respuesta porque contiene la información sobre el cambio de código que tenía que hacer. Creé una variable de puntero en el almacenamiento de trabajo. Cambié la llamada para usar la sintaxis "RETURNING INTO myPointer" y usé el comando Set Address Of como sugirió. Gracias de nuevo. –

Cuestiones relacionadas