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.
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. –
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. –