#include %VHMacro #include %occInclude AsyncFopStatus(DocBaseID,Status,NumberOfPages,DocURL) #define FopJobLookup(%id) ^Sys.Event.Lookup("FOP","fopJobID",%id) #define SFSLookup(%key) ^Sys.Event.Lookup("FOP","SFSKey",%key) Quit:($G(DocBaseID)="") New %blFOPDocBase,Rslt,blnQuit Set %PrefixWL=">SFS: " Do RestartTimer^vhLib() Hang 0.05 ; Delay this process, timeshift simplifies the order of events in case of (DocBase config) Sync mode! Do WLIP^vhDBG(97,$G(%PrefixWL)_"FopStatus triggered --> Jobbed by WS (JobID="_$J_")") If '$$afsLookup(DocBaseID) Do . Set $$$SFSLookup("SFS\"_DocBaseID)=$J . d WL^vhDBG($G(%PrefixWL)_"Waiting for Signal (LookupViaSFSKey:"_"SFS\"_DocBaseID_")") . Set Rslt=$SYSTEM.Event.Wait("",10) . Kill $$$SFSLookup("SFS\"_DocBaseID) ; Wait-event signalled or timed out --> lookup no longer needed . If Rslt=0 Do .. Set blnQuit=0 ; decide if routine should quit in case of a wait timeout. .. ; Log that SFS wait has timed out --> TO DO ! Quit:($G(blnQuit,0)) Set:('$G(%blFOPDocBase)) %blFOPDocBase=$System.OBJ.New("BL.FOP.DocBase.TestWS") Do %blFOPDocBase.OnSendFOPStatus(.DocBaseID,.Status,.NumberOfPages,.DocURL) Set $ZTRAP="" Quit afsLookup(DocBaseID) Quit $$$aHasData($$$FopJobLookup(DocBaseID)) afsFopStatusError Set $ZTRAP="" d WL^vhDBG($G(%PrefixWL)_"Error in Job AsyncFopStatus): "_$$$CRLF_$ZE) Set $ZE="" Quit // Calls the FopProcess() method in a separate thread. // Returns nothing, signal a process (lookup JobID) when the DocBase process (via WS) has finished, ONLY if the SendFOPStatus task is included !!! // Apply next lines into your code to SIMULATE an Async FopProcess() call : // // Job FopProcessSyncInThread(fopReq,TimeOut,blnPeek) // Set fopJobID=$ZCHILD // Quit fopJobID FopProcessSyncInThread(fopReq,TimeOut,blnPeek) #define FopJobLookup(%id) ^Sys.Event.Lookup("FOP","fopJobID",%id) #define SFSLookup(%key) ^Sys.Event.Lookup("FOP","SFSKey",%key) New fopReqID,fopRes,fopJobID,DocBaseID,msg,Rslt,sc New %blFOPDocBase Hang 0.01 Set %PrefixWL=">ASYNC: " Set $ZTRAP="fpsInThreadError" d WLIP^vhDBG(97,$G(%PrefixWL)_"Started FopProcessSyncInThread() --> $J="_$J) Set:('$G(%blFOPDocBase)) %blFOPDocBase=$System.OBJ.New("BL.FOP.DocBase.TestWS") Do fpsOpenRequestObj() Set fopRes=%blFOPDocBase.FopProcess(fopReq,.TimeOut,.blnPeek) ;Set fopRes=..FopProcess(fopReq,.TimeOut,.blnPeek) Set fopJobID=$J ; Use as simulated fopJobID, instead of the real fopRes.jobID Set:($IsObject(fopRes)) DocBaseID=fopRes.jobID If $L($G(DocBaseID)) Do . Merge $$$FopJobLookup(DocBaseID)=$$$FopJobLookup(fopJobID) . Set Rslt=%blFOPDocBase.SignalViaSFSKey("SFS\"_DocBaseID,.msg) Set sc=$$fpsHandleFopResponse() If $$$ISERR(sc) Do . Kill:($L($G(DocBaseID))) $$$FopJobLookup(DocBaseID) ; It will not be used because SendFopStatus will not be triggered . ; Set StatusFromFopResponse . Kill ^Sys.FOP.Log("ByJOB",fopJobID) . Set ^Sys.FOP.Log("ByJOB",fopJobID)=sc . ; Signal the parent job if waiting . Set Rslt=%blFOPDocBase.SignalViaFopJobID(fopJobID,.msg) Do fpsRemoveRequestObj() Set $ZTRAP="" Quit fpsOpenRequestObj() Quit:($IsObject(fopReq)) ; Else: Open Request object via ID Set fopReqID=fopReq Set fopReq=##class(WS.FOP.WSRequestInfo).%OpenId(fopReqID) Set:(fopReq.data=" ") fopReq.data="" Set:(fopReq.dataRef=" ") fopReq.dataRef="" ;Set fopReq.dataRef=$E(fopReq.dataRef,1,45) // Temp Test to create an ERROR on purpose!!! ;d WL^vhDBG($G(%PrefixWL)_"Opened FopRequest object: "_$G(fopReq)) Quit fpsRemoveRequestObj() Set fopReqID=fopReq.%Id() Quit:(fopReqID="") Set fopReq="" Set sc=##class(WS.FOP.WSRequestInfo).%DeleteId(fopReqID) Quit fpsHandleFopResponse() Quit:('$IsObject(fopRes)) $$$ERROR($$$GeneralError,"No Response Object") Set sc=%blFOPDocBase.HandleFopResponseError(fopRes,fopReq) Quit sc fpsInThreadError Set $ZTRAP="" d WL^vhDBG($G(%PrefixWL)_"Error in Job (FopProcessSyncInThread): "_$$$CRLF_$ZE) Set $ZE="" Quit /* AsyncFopStatus(DocBaseID,Status,NumberOfPages,DocURL) #define LogStatusSFS(%id) ^Sys.Event.Logging("FOP-SFS",%id) ;quit Quit:($G(DocBaseID)="") New %blFOPDocBase,Rslt Set $$$LogStatusSFS(DocBaseID)="Inited" Set $ZTRAP="afsFopStatusError" Do WLIP^vhDBG(97,">SFS: FopStatus triggered --> Jobbed by WS (JobID="_$J_")") ;Do RestartTimer^vhLib() Set ^Sys.Event.Lookup("FOP","fopJobID","SFS\"_DocBaseID)=$J Set $$$LogStatusSFS(DocBaseID)="Waiting" ;d WL^vhDBG(">SFS: Waiting for Signal ") Set Rslt=$SYSTEM.Event.Wait("",10) ;d WL^vhDBG(">SFS: continue after waiting. Result: "_Rslt) Kill ^Sys.Event.Lookup("FOP","fopJobID","SFS\"_DocBaseID) ; Wait event signalled or timed out --> lookup no longer needed If Rslt=0 Do Quit . Set $$$LogStatusSFS(DocBaseID)="TimedOut" . ; Log timed out ; Else Set:('$G(%blFOPDocBase)) %blFOPDocBase=$System.OBJ.New("BL.FOP.DocBase.TestWS") Do %blFOPDocBase.OnSendFOPStatus(.DocBaseID,.Status,.NumberOfPages,.DocURL) Set $$$LogStatusSFS(DocBaseID)="Finished" Set $ZTRAP="" Quit afsFopStatusError Set $ZTRAP="" Set $$$LogStatusSFS(DocBaseID)="Error" d WL^vhDBG("Error in Job AsyncFopStatus): "_$$$CRLF_$ZE) Set $ZE="" Quit // Calls the FopProcess() method in a separate thread. // Returns nothing, doesn't signal a process (lookup JobID) when the DocBase process (via WS) has finished. // Apply next lines into your code to SIMULATE an Async FopProcess() call : // // Job FopProcessSyncInThread(fopReq,TimeOut,blnPeek) // Set fopJobID=$ZCHILD // Quit fopJobID // // ATTENTION: Do not include the SendFOPStatus task in the DocBase Process with sync-mode! // It will attempt to trigger a Signal on the real fopJobID. FopProcessSyncInThread(fopReq,TimeOut,blnPeek) New fopReqID,fopRes,fopJobID,msg,Rslt New %blFOPDocBase Set $ZTRAP="fpsInThreadError" d WLIP^vhDBG(97,"Started FopProcessSyncInThread() --> $J="_$J) Set:('$G(%blFOPDocBase)) %blFOPDocBase=$System.OBJ.New("BL.FOP.DocBase.TestWS") Do fpsOpenRequestObj() d WL^vhDBG("Start FopProcess: "_$G(fopReq)) Set fopRes=%blFOPDocBase.FopProcess(fopReq,.TimeOut,.blnPeek) ;Set fopRes=..FopProcess(fopReq,.TimeOut,.blnPeek) Set fopJobID=$J ; Use as simulated fopJobID, instead of the real fopRes.jobID Do fpsSimulateSendFOPStatus() d WL^vhDBG("fopRes: "_$G(fopRes)) If $IsObject(fopRes) Do . ; Log Response . Set sc=%blFOPDocBase.HandleFopResponse(fopRes,fopReq) ;Set sc=..HandleFopResponse(fopRes,fopReq) Do fpsRemoveRequestObj() Set $ZTRAP="" Quit fpsOpenRequestObj() Quit:($IsObject(fopReq)) ; Else: Open Request object via ID Set fopReqID=fopReq Set fopReq=##class(WS.FOP.WSRequestInfo).%OpenId(fopReqID) Set:(fopReq.data=" ") fopReq.data="" Set:(fopReq.dataRef=" ") fopReq.dataRef="" Quit fpsRemoveRequestObj() Set fopReqID=fopReq.%Id() Quit:(fopReqID="") Set fopReq="" Set sc=##class(WS.FOP.WSRequestInfo).%DeleteId(fopReqID) Quit fpsSimulateSendFOPStatus() Set Rslt=%blFOPDocBase.SignalViaFopJobID("SFS\"_fopJobID,.msg) d:($L($G(msg))) WL^vhDBG("SignalViaFopJobID: "_msg) Quit fpsInThreadError Set $ZTRAP="" d WL^vhDBG("Error in Job (FopProcessSyncInThread): "_$$$CRLF_$ZE) Set $ZE="" Quit */ /* * / /// Call DocBase WS process via sync method. The response is returned by reference (.local SyncResponse) ClassMethod CallWSProcessSync(fopReq As WS.FOP.WSRequestInfo, ByRef fopRes As WSResponse, TimeOut As %Integer, blnPeek As %Boolean) As %Status { ;New cl,jobID,sc ;New CustomMsg Set cl=$System.OBJ.New("WS.FOP.DocBase") Set sc=..PrepareWSClient(.TimeOut,.blnPeek) Quit:($$$ISERR(sc)) sc ;d WL^vhDBG("SOAP Client class: "_cl_$$$CRLF_$$ObjToText^vhLib(cl)) d WL^vhDBG($G(%PrefixWL)_"Invoke DocBase WS ""fopRes=cl.process(fopReq)"" ... ") Do cpsFopProcessSub() d WL^vhDBG($G(%PrefixWL)_"Finished DocBase cl.process: Result: "_$G(fopRes)) Quit sc cpsFopProcessSub() Set fopRes="" ;Quit:(locIndx<0) Set $ZTRAP="cpsSoapErrorWSSync" Set fopRes=cl.process(fopReq) Set $ZTRAP="" Quit cpsSoapErrorWSSync Set $ZTRAP="" Set sc=$$$ERROR($$$GeneralError,"Error in FOP web service: CallWSProcessSync() method.") Do ..SoapErrorHandler() Set $ZE="" Quit } /// Call DocBase WS via Async method. The JobID of the async DocBase process/thread is returned immediatly (.local JobID) ClassMethod CallWSProcessAsync(fopReq As WS.FOP.WSRequestInfo, ByRef JobID As %String, TimeOut As %Integer) As %Status { ;New cl,sc,jobID ;New CustomMsg Set cl=$System.OBJ.New("WS.FOP.DocBaseAsync") Set sc=..PrepareWSClient($G(TimeOut,20),0) Quit:($$$ISERR(sc)) sc ;d WL^vhDBG("SOAP Client class: "_cl_$$$CRLF_$$ObjToText^vhLib(cl)) d WL^vhDBG($G(%PrefixWL)_"Invoke DocBase WS ""fopRes=cl.process(fopReq)"" ... ") Do cpaFopProcessSub() Set jobID=$G(jobID) d WL^vhDBG($G(%PrefixWL)_"Finished DocBase cl.process: Result: "_$G(jobID)) Quit sc cpaFopProcessSub() Set fopRes="" ;Quit:(locIndx<0) Set $ZTRAP="cpaSoapErrorWSAsync" Set jobID=cl.startRequest(fopReq) ; next lines ??? ;Set fopRes=$System.OBJ.New("WS.FOP.WSResponse") ; WS.FOP.WSAsyncResponse ;Set fopRes.jobID=jobID Set $ZTRAP="" Quit cpaSoapErrorWSAsync Set $ZTRAP="" Set sc=$$$ERROR($$$GeneralError,"Error in FOP web service: CallWSProcessAsync() method.") Do ..SoapErrorHandler() Set $ZE="" Quit } /* */