Consuming managed web services from the ABL

Posted by mad_englishman66 on 05-Aug-2010 04:35

Hi guys,
For a few years we have been using proxies generated by ProxyGen to provide access to 4GL running on AppServer. The business logic contains a number of standard library functions which handle things including application level security. This is all based around using SESSION:SERVER-CONNECTION-ID on a stateless AppServer to establish and control user context.
We would now like to expose a small sub-set of the programs as web services using the WSA and web services for use with mobile devices. Again, the web services will be generated using ProxyGen. I have had test calls to web services working using non managed web services and a state free AppServer but now need to move this on to be managed so that the standard application security we have can also be implanted in this environment.
I have generated the web services using the managed option in ProxyGen and changed the operating mode of the AppServer to stateless. I have connected to my web service and created the object but when I then make a call to do something I correctly receive a SOAP fault which is saying that I do not have the UUID set. What I am not able to do using the Progress documentation is work out how I retrieve the UUID from the header and assign it back for subsequent calls.
Following the documentation I believe that I need to use SET-CALLBACK-PROCEDURE to set a procedure in which to access the SOAP header via its handle. I have tried this approach but the procedure is not be called and I am not finding the documentation clear in order to work out where I am going wrong.
Does anyone have a small sample of code that does the following for a managed web service retrieving and setting the appropriate UUID:
  1. Connects      to a web service
  2. Creates      the web service object
  3. Performs      web service request 1
  4. Performs      web service request 2
  5. Disconnects      and tidies up
Assuming that I get this working, will the SESSION:SERVER-CONNECTION-ID contain a unique entry per connection or will I need to do something different to retrieve this type of information?
Many thanks in advance
Phil Brown.

All Replies

Posted by maximmonin on 05-Aug-2010 06:51

Here is flex code example to work with UUID

for Persistent_Object though but i am pretty sure it works for stateless model too.

when proxygen generates WSDL there are 2 ports in it.

One port works for session creation/persistent object creation.

and second port for communication. You have to supply UUID in header for every soap packet.

srvEdit.wsdl = editservicepath;

srvEdit.port = "DocEditorObj";

ReleaseRemoteObject = new Operation(null, "Release_DocEditor");

ReleaseRemoteObject.addEventListener(ResultEvent.RESULT, OnReleaseObject);

ReleaseRemoteObject.addEventListener(FaultEvent.FAULT, Onfault2);

srvEdit.operations = [ReleaseRemoteObject];

srvEdit.loadWSDL();

.....

var srv:WebService = new WebService();

srv.wsdl = editservicepath;

srv.port = "Oblik_DocEditorObj";

var CreateRemoteObject:Operation = new Operation(null, "CreatePO_DocEditor");

CreateRemoteObject.addEventListener(ResultEvent.RESULT, OnDocEditorObject);

CreateRemoteObject.addEventListener(FaultEvent.FAULT, Onfault2);

srv.operations = [CreateRemoteObject];

srv.loadWSDL();

CreateRemoteObject.send(EditContextId, RidDoc, ViewOnly, RidTypedoc, NewDoc, putoff, RidMainDoc, EditMode);

private function OnDocEditorObject(event:ResultEvent):void

{

     var xmlStr:String = event.headers.toString();

     var xmlDoc:XMLDocument = new XMLDocument(xmlStr);

     var decoder:SimpleXMLDecoder = new SimpleXMLDecoder(true);

     var headerObj:Object = decoder.decodeXML(xmlDoc);

/*           

Alert.show(ObjectUtil.toString(headerObj));

*/              

     var RemoteObjectId:String = headerObj.DocEditorID.UUID;

     srvEdit.clearHeaders();

     srvEdit.addSimpleHeader("DocEditorID", "urn", "UUID", RemoteObjectId);

    if (event.result.OutMessage != "")
    {
         ReleaseRemoteObject.send();
    }
....
}
I recommend to download free soapUI tool to test your webservice manually to understand what soap packets you have to generate.

Maxim.

Posted by mad_englishman66 on 06-Aug-2010 09:06

Thanks Maxim,

Although your code didn't help in terms of the Progress that was required, it did help me to decide on my lines of thinking. I have now managed to achieve what I set out to do. Whan follows is a copy of my sample code should anyone else find it of use.

Phil Brown.

/* This sample code connects to a managed web service on WSA / Tomcat */
/* with an AppServer running in stateless mode. This allows us to     */
/* identify and maintain user context on the server where this is     */
/* important for things such as application level security.           */

DEF VAR w-SOSConnectObj     AS HANDLE NO-UNDO.
DEF VAR w-Header            AS HANDLE NO-UNDO.
DEF VAR w-Test              AS CHAR FORMAT "x(100)" NO-UNDO.
DEF VAR w-WebService        AS HANDLE NO-UNDO.

/* Create the web service object. */
CREATE SERVER w-WebService.

/* Connect to the web service on the WSA. */
w-WebService:CONNECT("-WSDL 'http://sos-Phil-Old:8080/wsa/wsa1/wsdl?targetURI=urn:SOSConnect'
                     -Service SOSConnectService
                     -Port SOSConnectObj").

IF w-WebService:CONNECTED() THEN DO:
  /* Initialise the object. */
  RUN SOSConnectObj SET w-SOSConnectObj ON w-WebService.

  /* Define callback procedures which will be called on submission    */
  /* and return to / from each web service call. These are not        */
  /* required for non-managed web services but are essential in a     */
  /* managed environment. The issue is that for each call we need to  */
  /* supply a consistent UUID in the SOAP header to the WSA otherwise */
  /* the call will be rejected. The UUID is generated by the WSA.     */
  w-SOSConnectObj:SET-CALLBACK-PROCEDURE("REQUEST-HEADER","SoapRequestHeader").
  w-SOSConnectObj:SET-CALLBACK-PROCEDURE("RESPONSE-HEADER","SoapResponseHeader").

  /* Connect_SOSConnect is automatically generated in the web service */
  /* by ProxyGen and is used a little like a dummy call to initialise */
  /* the UUID. When the call returns SoapResponseHeader will be       */
  /* called and we can save the handle to the SOAP header. Rather     */
  /* than extracting the UUID from the SOAP header, by storing the    */
  /* handle to the SOAP header we can simply re-use it for all        */
  /* subsequent calls.                                                */
  RUN Connect_SOSConnect IN w-SOSConnectObj ("","","").

  /* Make whatever calls are required. Prior to each call             */
  /* SoapRequestHeader will be called and it is here that we assign   */
  /* the SOAP header (which contains the UUID) to be used for the     */
  /* call. SoapResponseHeader will also be called on return but as we */
  /* already have the handle to the original SOAP header we delete    */
  /* the newly returned one. NO-ERROR is used for each call as if not */
  /* and communication is lost to the WSA, the program will crash     */
  /* out. If communication is restored then subsequent calls can      */
  /* still be serviced and user context is maintained which is a      */
  /* bonus.                                                           */
  w-Test = "".
  RUN helloworld1 IN w-SOSConnectObj (OUTPUT w-Test) NO-ERROR.
  MESSAGE w-Test
    VIEW-AS ALERT-BOX.

  w-Test = "".
  RUN helloworld2 IN w-SOSConnectObj (OUTPUT w-Test) NO-ERROR.
  MESSAGE w-Test
    VIEW-AS ALERT-BOX.

  w-Test = "".
  RUN helloworld3 IN w-SOSConnectObj (OUTPUT w-Test) NO-ERROR.
  MESSAGE w-Test
    VIEW-AS ALERT-BOX.

  RUN Release_SOSConnect IN w-SOSConnectObj.

  DELETE OBJECT w-SOSConnectObj.
  w-WebService:DISCONNECT().
END.

DELETE OBJECT w-WebService.

PROCEDURE SoapResponseHeader:
  DEF INPUT PARAM pi-SOAPHeader         AS HANDLE.
  DEF INPUT PARAM pi-OperationNamespace AS CHAR.
  DEF INPUT PARAM pi-OperationLocalname AS CHAR.

  IF NOT VALID-HANDLE(w-Header) THEN  /* First response. */
    w-Header = pi-SOAPHeader.
  ELSE  /* All subsequent responses. */
    DELETE OBJECT pi-SOAPHeader.
END PROCEDURE.

PROCEDURE SoapRequestHeader:
  DEFINE OUTPUT PARAMETER pi-SOAPHeader AS HANDLE.
  DEF INPUT PARAM pi-OperationNamespace AS CHAR.
  DEF INPUT PARAM pi-OperationLocalname AS CHAR.
  DEFINE OUTPUT PARAMETER lDeleteOnDone AS LOG.

  DEFINE VARIABLE hsheEntry AS HANDLE.

  IF NOT VALID-HANDLE(w-Header) THEN  /* First Request. */
    pi-SOAPHeader = ?.
  ELSE  /* All subsequent responses. */
    ASSIGN pi-SOAPHeader = w-Header
           lDeleteOnDone = FALSE.
END PROCEDURE.

This thread is closed