User wants an APPL to confirm when a UBE is complete

johndanter

johndanter

Legendary Poster
Hi folks,

I have an issue in which an APPL will call a UBE but we are required to tell the user the UBE is finished and they can move on to the next step. (yes they wait :))

UBE is R31410, APPL is custom

Now I know I can't call a UBE synchronously from an APPL anymore. So how do I get around that?
If I write a NER to call a UBE the server gets upset as it's spawning a synchronous thread.....

But if I write a C++ BSFN and use the launch API BSFN with the synch flag = TRUE, whats' the difference between that and a direct call in a NER

https://support.oracle.com/epmos/fa...afrWindowMode=0&_adf.ctrl-state=f4a7d7pbs_165

Can I cheat by calling a UBE asynch and then in the UBE calling a UBE synchronously (that's not going to work either, right)
Or is this hinting that it will work?
Option 2

https://support.oracle.com/epmos/fa...te=f4a7d7pbs_9&_afrLoop=385718480603462#CAUSE

Thanks

John
 
Last edited:
Why can't they use the standard E1 "Recent reports" panel to check the status of the report and then proceed? This functionality was included precisely for this reason (and to allow users to quickly download reports).
 
I have to call a BSFN myself when the UBE is finished and notify them the BSFN worked.

I can add the BSFN to the end of the UBE I guess

That said, if I write a C+ BSFN to use the API, I can control the launch of the UBE and I can do it synchronously, right?
As APPLs do wait for a BSFN to execute.

I'm just confused as to why it may work with C+ API but not the direct UBE RI call in the NER
 
Last edited:
There is a sync flag in the UBEVAR (bSynchFlag). I have done quite a few of these but I always set it to FALSE for the server compile so I don't know if it actually uses it or not when it runs on the ES (probably depending on your tools release???) - it may always run async when the BSFN executes on the ES????

Regardless, it is a little dangerous to run sync if that BSFN is ever called from an APPL because you risk BSFN timeout if the UBE is held up for whatever reason. When I have had to do things like what you are talking about (and we have several applications that work much like you describe) I have a general purpose BSFN that polls the running UBE (checks status, sleep, checks status, sleep, etc.). That way I can control how long the BSFN waits before returning a response to the APPL and if the UBE takes too long I can come back with a nice friendly message instead of them getting the generic "There was a problem with Business Function..." JAS message and even give the user the opportunity to continue to wait for the UBE to complete. The polling BSFN was not trivial, namely because it can be tricky to get the Job Status data source, especially if you have a configuration like we do where we have basically rolled our own virtual BAT servers, so if you go that route it may take a little work- but once you get it working you can re-use so....
 
I'll leave this here relevant youtube link

https://www.youtube.com/watch?v=KX5jNnDMfxA

Ha ha class film too.

Listen folks, this isn't me asking. I've said you can't have an APPL waiting. It's silly. It's the people above me trying to design a soln that may not work the way they desire it to.

I've just written a simple APPL to get the time before and after a call to a new BSFN I've written that wraps up a UBE call using jdeLaunchUBEEx

So I'll get it promoted and let you knwo if it actually works in SYNCH mode or not. I don't think it will


Other option is to get all the code inside R31410 and create a mimick BSFN that I can call.
Does anyone know of such a BSFN?
 
I have a general purpose BSFN that polls the running UBE (checks status, sleep, checks status, sleep, etc.). That way I can control how long the BSFN waits before returning a response to the APPL and if the UBE takes too long I can come back with a nice friendly message instead of them getting the generic "There was a problem with Business Function..."

I may go down this route too if all else fails. Or I was thinking about modding R31410 to write a work table I question in the APPL. A record written on the way in and then updated on the way out
They can query it in the APPL with a button then
 
Ok for future people reading this...........................It doesn't work :)

It works locally but when it goes on the APPL server and calls a BSFN to launch a job in SYNCH mode, you get this.......

Error UBE0000007: attempting to call Report and Version R570097 VJDE0001 synchronously from within a CallObject Kernel
 
That's right - you can't do Synch call to UBE from an app. That includes BSFNs running as part of the app.

Is it acceptable to email the End User notification that the job has finished? Maybe include the UBE output as a side benefit?
 
That's right - you can't do Synch call to UBE from an app. That includes BSFNs running as part of the app.

Is it acceptable to email the End User notification that the job has finished? Maybe include the UBE output as a side benefit?

Well I do have a nice little UBE that sweeps F986110 and it references a confog table for a match on UBE and VERS,
If found it can report to people the UBE is done. Even attaches the PDF/CSV to the email.
Sadly it's just the UBE is complete and not the specifics of what the UBE processed (in this case they want specific WO completions results in terms of DOCO)
 
I infer that your users are asking about UBEs that are submitted by a batch scheduler like Robot Scheduler. Solution: the batch scheduler can send email completion message to any recipient after UBE completes. If user is submitting his own UBE, E1 can email a completion message to submitter. Or look in Work Center
 
Listen folks, this isn't me asking. I've said you can't have an APPL waiting. It's silly. It's the people above me trying to design a soln that may not work the way they desire it to.

Well, you can do what they are asking. Like I said I have several APPLs that do just that (Put on into PD just this month). And too me it is a reasonable request - if I was a BA/End User I would ask for it as well and probably wouldn't understand why it couldn't be done. It just takes a little work to implement it. Once I had the UBE Status polling BSFN, the next implementation of the same design pattern was much easier.
 
Well, you can do what they are asking. Like I said I have several APPLs that do just that (Put on into PD just this month). And too me it is a reasonable request - if I was a BA/End User I would ask for it as well and probably wouldn't understand why it couldn't be done. It just takes a little work to implement it. Once I had the UBE Status polling BSFN, the next implementation of the same design pattern was much easier.

You are by all means welcome to kindly send me your PAR file Brian ;)

How did you launch your UBEs? I need to submit the UBE with RI values for a specific. So certain launch methods are out.
 
I don't mind giving the PAR file with the function... not like I am a CEO of a Silicon Valley startup giving the secret to a new compression algorithm that will reinvent the internet. :)

My only hesitation is that this BSFN works for us with our setup (OCM mappings, virtual BAT servers, etc.). In other words, your milage may vary so it may need tweaking to work for you. Also, there are some things you have to know/do to call it correctly (again, once you do it once the next time its easy... you just copy what you did before).

1. The simplest pattern will look like:

APPL
- MyBsfnToLaunchUbe (Must be a C BSFN)
---- Launch UBE via jdeLaunchUBEEx
---- Wait for UBE to complete by calling AcmeUbeUtilGetUbeStatus. Pass pointer handle to UBEVAR pointer via jdeStoreDataPtr


Example code that waits for UBE to complete:

Code:
static E5642138_UBE_STATUS 
I5642138_GetUbeStatus(	LPBHVRCOM lpBhvrCom, LPVOID lpVoid, 
								HUSER hUser,
								UBEVAR *pubevar,
								MATH_NUMERIC const *pmnUbeTimeOut,
								JCHAR *pszRPDFOutputRecordGUID, jde_n_char nRpdfGuidSize)
{
	DSD5800036A		ubeStatus={0};


	ubeStatus.idPtrHnd_PUBEVAR = jdeStoreDataPtr(hUser, pubevar);

	if(!ubeStatus.idPtrHnd_PUBEVAR)
	{
		jdeErrorSet (lpBhvrCom, lpVoid, (ID) 0, _J("4363"), (LPVOID) NULL); 
		return E5642138_UBE_STATUS_FINISHED_IN_ERROR;
	}

	MathNumericToInt((LPMATH_NUMERIC)pmnUbeTimeOut, &ubeStatus.nWaitForCompletionTimeOutMS);

	if(ubeStatus.nWaitForCompletionTimeOutMS < B5642138_DEFAULT_UBE_TIMEOUT_SECONDS)
		ubeStatus.nWaitForCompletionTimeOutMS = B5642138_DEFAULT_UBE_TIMEOUT_SECONDS;

	ubeStatus.nInitialWaitIntervalMS			= 2000;		/* initial wait of 2 seconds before first status check */
	ubeStatus.nWaitForCompletionTimeOutMS	= (ubeStatus.nWaitForCompletionTimeOutMS * 1000) - ubeStatus.nInitialWaitIntervalMS;
	ubeStatus.cWaitForCompletion				= _J('1');

	if(pszRPDFOutputRecordGUID)
		ubeStatus.cIsCheckForRptDefContent = _J('1');


	if(acmeCallObject(AcmeUbeUtilGetUbeStatus, lpBhvrCom, lpVoid, &ubeStatus) == ER_ERROR ||
		acmeIsTrue(ubeStatus.cJobNotFound) )
	{
		return E5642138_UBE_STATUS_FINISHED_IN_ERROR;
	}

	if(jdeStrcmp(ubeStatus.szJobStatus, _J("E")) == 0)
		return E5642138_UBE_STATUS_FINISHED_IN_ERROR;

	jdeStrncpy(pszRPDFOutputRecordGUID, ubeStatus.szRPDFOutputRecordGUID, nRpdfGuidSize - 1);
	return acmeIsTrue(ubeStatus.cJobComplete) ? E5642138_UBE_STATUS_FINISHED : E5642138_UBE_STATUS_WAITING;
}


2. It's hard to test on a Web Dev Client. To test when running locally you still have to submit the UBE to an actual batch server. I usually have a provision right in the MyBsfnToLaunchUbe function specifically for testing locally to launch to an actual server, which also usually involves something in processing options of the APPL to list the batch server and queue to use when running local:

Example of launching a UBE to a server when run on WebDev client:
Code:
JDEBFRTN (ID) JDEBFWINAPI AcmeSoePrintSalesQuoteSilent (LPBHVRCOM lpBhvrCom, LPVOID lpVoid, LPDSD5642140A lpDS)  
 
{ 
   /************************************************************************ 
    *  Variable declarations 
    ************************************************************************/ 
	ID						idReturn = ER_SUCCESS;
	HUSER					hUser = (HUSER)NULL;
	DSRIR56428010		ri={0};
	UBEVAR				ube={0}, *pubevar=(PUBEVAR)NULL;
	JCHAR					szLocalComputerName[16]={0}, szEnvironmentName[11]={0};

   /************************************************************************ 
    * Check for NULL pointers 
    ************************************************************************/ 
   if ((lpBhvrCom == (LPBHVRCOM) NULL) || 
       (lpVoid    == (LPVOID)    NULL) || 
       (lpDS      == (LPDSD5642140A)	NULL)) 
   { 
     jdeErrorSet (lpBhvrCom, lpVoid, (ID) 0, _J("4363"), (LPVOID) NULL); 
     return ER_ERROR; 
   } 
 
   /************************************************************************ 
    * Main Processing 
    ************************************************************************/ 
	if(IsStringBlank(lpDS->szVersion))
   { 
		jdeErrorSet (lpBhvrCom, lpVoid, (ID) 0, _J("4363"), (LPVOID) NULL);
		return ER_ERROR;
   } 


	/********** Get User Handle **********/
	if( (idReturn = acmeInitBhvr(lpBhvrCom, lpVoid, &hUser, (JCHAR *)NULL, JDEDB_COMMIT_AUTO)) != ER_SUCCESS )
		return ER_ERROR;



	/********** Get Pass Ptr Handles **********/
	if(lpDS->idPtrHnd_UBEVAR_RetBuf)
	{
		pubevar = jdeRemoveDataPtr(hUser, lpDS->idPtrHnd_UBEVAR_RetBuf);

		if(!pubevar)
		{
			jdeErrorSet (lpBhvrCom, lpVoid, (ID) 0, _J("4363"), (LPVOID) NULL); 
			idReturn = ER_ERROR;
			goto FunctionCleanUp;
		}
	}

 

	/***** Call the UBE *****/

	/* set the ube report interconnects */
	jdeStrncpy(ri.szOrderCompany,	lpDS->szOrderCompany, DIM(ri.szOrderCompany)-1);
	jdeStrncpy(ri.szOrderType,		lpDS->szOrderType, DIM(ri.szOrderType)-1);
	MathCopy(&ri.mnDocumentOrderInvoiceE, &lpDS->mnOrderNumber);


	/* set the launch ube vars */
	jdeGetHostName(szLocalComputerName, DIM(szLocalComputerName), 0); 
	GetLocalEnvironmentName(szEnvironmentName, DIM(szEnvironmentName));

	jdeNIDcpy(ube.szReport,			_J("R56428010"));
	jdeNIDcpy(ube.szVersion,		lpDS->szVersion);
	jdeStrcpy(ube.szMachineKey,	szLocalComputerName);
	jdeStrcpy(ube.szEnhv,			szEnvironmentName);
	ube.bBatchFlag						= TRUE;
	ube.idRunTime						= (GLRTID)(lpBhvrCom->hDlg)<<16;
	ube.bSynchFlag						= !acmeIsTrue(lpDS->cIsAsync);

#ifdef IAMASERVER
	ube.bPreview						= FALSE;
#else //LOCAL WEB DEV
	if(!IsStringBlank(lpDS->szLocalWebDevBatchServer)
		&& !IsStringBlank(lpDS->szLocalWebDevJobQueue))
	{
		ube.bPreview						= FALSE;
		jdeStrncpy(ube.szHostName,		lpDS->szLocalWebDevBatchServer, DIM(ube.szHostName)-1);
		jdeStrncpy(ube.szJobQueue,		lpDS->szLocalWebDevJobQueue, DIM(ube.szJobQueue)-1);
	}
		else
			ube.bPreview = TRUE;
#endif //IAMASERVER


	/* launch the ube and exit */
	jdeLaunchUBEEx(hUser, &ube, &ri, lpBhvrCom);

	if(pubevar)
		memcpy(pubevar, &ube, sizeof(*pubevar));


   /************************************************************************ 
    * Function Clean Up 
    ************************************************************************/ 
FunctionCleanUp:


	/* free user */
	if(hUser)
		JDB_FreeBhvr(hUser);
		
	return idReturn;
}
 

Attachments

  • PRJ_bgo.59.UBEUTILS_60_99.zip
    18.5 KB · Views: 20
  • ListOfObjects.JPG
    ListOfObjects.JPG
    25.9 KB · Views: 15
John,

This may be moot if you go with Brian's functionality, but on a custom application (that runs a UBE which updates a custom status code in a custom table) I have a refresh button that reads and updates the status on the form. User's don't get notified as such, but they can click the refresh to get the current status.

The other option that came to mind is the automatic email that notifies the user that the UBE is finished. But that is probably switched off in your system.
 
Back
Top