Dayalan Punniyamoorthy Blog

Wednesday, November 16, 2022

Calling Data Management Rule from Calculation Manager rule using Groovy!

null

This was always a special request from multiple customers Can I run Data Management rules from a form?  For quite a while the answer was sorry you cannot. But with Groovy + Calculation Manager you can do that. Yes, you can call the Data Management rule from a Calculation manager rule and attach the Calculation Manager rule to a Menu and attach that Menu to the Form, so the users can run them when needed.

The next question is if the User id is not an Admin user, will he be still able to run the Data Management rule. As per the Oracle EPM security setup you cannot.

But you can overcome this by using Connections either by using On Demand Connections or Named Connections.

A Brief intro on when to use when, (from the Oracle document)

In general, connections can be created in one of two ways:

On-demand connection

  Connection connection = connection(http://server:port/HyperionPlanning/rest/v3/applications/Vision, "user", "password")
These connections are easy to change and are great for prototyping and trying out connections.

Named connection

  Connection connection = operation.application.getConnection("Job Definitions")
These connections allow clean separation between resource details and usage. This has multiple benefits over on-demand
connections including:

  • Ease of maintenance - Reuse a connection definition in multiple scripts. Any changes to the definition will automatically apply to all scripts using the named connection.
  • Enhanced security - with on-demand connections, confidential information such as passwords and API keys are visible to anyone who can edit the Groovy script. With named connections, sensitive information can be encrypted and stored securely and cannot be seen or retrieved by Groovy scriptwriters.
  • Ease of use - simplifies the creation of connections to first-party resources such as Oracle Cloud Services.

Ok now back on track, let's see a real-world example where I did implement this.  The request was to send the Actual data that was loaded in a Sales cube (Source) to the Finance cube (Target) both cubes are created in two different instances on demand using a Data form.

Step 1: Create a cross-application Data Management Rule that will pull the Actual data from the Sales cube (Source) and push that to the Finance cube (Target). (Will create a separate blog on this, if I receive any clarification on how to do that)

Step 2: Create a Connection in the instance where you will be creating/running the Calculation Manager rule. I create a Named connection so the password of the Admin is not compromised.

Step 3: Create a Calculation Manager business rule with Groovy capabilities. Call the Data Management rule created in Step 1 via the rule using the Connection created in Step 2.  

I will be focusing only on Step 3 in this blog,

Step 4: Create a Menu and attach the Business rule created above to it.

Step 5: Attach the Menu created above to the Data Form.

_________________________________________________________________________________

Step 3: Explained in detail 


Calling the connection and calling the job along with the parameters to run the Data Management rule.

Do note the some of the Parameters are mandatory and I am listing the ones that needs to be specified.



Note: 

If you use any other period naming parameter other than the parameters described above, you get an "Invalid Input – HTTP 400 " error message.

Lot of flexibility in passing the period values, I have used Subsititition variables in my code. 



You can choose the best one as per the requirement but these needs to be specified to invoke the Data Management rule.  The ones I did used are highlighted for easy understanding. 


The rest of the code will get the status of the Data Management rule and also waits for the job to finish to ger the execution status. 

Do note I have used two different instance to send the data via Data Managment, but you can use the same instance to perform the same action. In the connection conned to the same instance and you should be good.

Hope this was useful, happy days ahead on the Oracle EPM Cloud!

The Complete rule:

//*******************************************************************************************

//This rule is to run the Data Management rule "DataManagement_Rule"  using the Connection details "To_Connect_Instance_WhereDMRuleCreated" to transfer the data (Actual,Budget, etc..) from Source Planning application Source cube to Target application Target cube. 

//*******************************************************************************************


// Call Data Management POST REST API. 

 HttpResponse<String> jsonResponse = operation.application.getConnection("To_Connect_Instance_WhereDMRuleCreated").post().body(json(["jobType":"INTEGRATION", "jobName":"DataManagement_Rule", "periodName":"{&OEP_CurMnth#&OEP_CurYr}", "importMode":"REPLACE", "exportMode":"Merge"])).asString();

 def status = awaitCompletion(jsonResponse, "To_Connect_Instance_WhereDMRuleCreated")

 println("Push Actual data from 'Source Planning application Source cube to Target application Target cube.' is  ${status == 0 ? "successful" : "failed"}.\n")

 // Wait for DM job to be completed

 def awaitCompletion(HttpResponse<String> jsonResponse, String connectionName) {

     final int IN_PROGRESS = -1

     if(!(200..299).contains(jsonResponse.status))

         throwVetoException("Error occured: $jsonResponse.statusText")

     // Parse the JSON response to get the status of the operation. Keep polling the To_Connect_Instance_WhereDMRuleCreated server until the operation completes.

     ReadContext ctx = JsonPath.parse(jsonResponse.body)

     def object = new JsonSlurper().parseText(jsonResponse.body)

    println object         

     int status = ctx.read('$.status')

     for(long delay = 50; status == IN_PROGRESS; delay = Math.min(1000, delay * 2)) {

         sleep(delay)

         status = getJobStatus(connectionName, (String)ctx.read('$.jobId'))

          }

     return status  

 }

 // Call Finance instance GET REST API to poll the Data Management for job status

 int getJobStatus(String connectionName, String jobId) {

     HttpResponse<String> pingResponse = operation.application.getConnection(connectionName).get(jobId).asString()

     return JsonPath.parse(pingResponse.body).read('$.status')

            

 }

______________________________________________________________________________ 

 




 

 

 

 

 

 

 

 

 

 

 

 

 

 

No comments:

Post a Comment