Data Push for Non-Administrator Users

An interesting situation presented itself the other day.  We have a process set up to copy actuals to a selected forecast scenario and push the data to the reporting cube.  The process works well, a ruleset executes a standard business rule to do the copy, and then a Groovy business rule to launch the data map for the push to reporting.  The problem is that only service administrators can execute the ruleset since non-administrators do not have access to data maps. 

I vaguely remembered reading about using Groovy to have a non-administrator execute data maps.  I reached out to co-workers and several provided a way to do it.  Note: I am not yet proficient with Groovy, I’m still learning, so while this coding works for my example, there may be better ways to code it.

The first step is to set up a connection in the planning application that points back to the same application.  The connection is configured with the credentials of a service administrator. 

The URL and Service Administrator credentials have to be structured as shown.

  1. URL appended with HyperionPlanning
  2. Username prefixed with the domain name

Validate the connection and then click Save and Close.  Remember the name used for the connection.

Now we create a Groovy rule that calls the existing rule that executes the data map. 

The new rule starts with string variables replacing double quotes with no space in the variables from the existing rule. 

Then we define what rule to execute for the data map and pass in the string variables to that rule.

1. Name of Groovy rule that calls data map

A json string is configured to execute the job defined in the previous step.

Additional code is added to monitor the REST job to completion.

We now have a rule that when executed will launch another rule using the credentials of a service administrator.  In the ruleset originally set up to perform the data copy and push the data to the reporting cube, we replaced the Groovy rule calling the data map with this new rule. 

Normal access control settings can be applied to this new rule limiting its availability to specific users, so there is still control over the use of the data map.  But it allows us the flexibility to let non-administrative users execute tasks otherwise limited to administrators. 

As always, happy EPM’ng!

Special thanks to my fellow interRelites Ronnie Tafoya, Dyana Karcher, and Shane Eckert.

Here’s the complete rule for easy copying:

/* use Loopback_Rest connection to push data to reporting cube */
/*RTPS: {PeriodVarFinPln}, {YearVarFinPln}, {FcstScenarioVarFinPln}, {FcstVersionVarFinPln} */
 
/* Set string variables for RTPS values replacing double quotes with no space */
String strScenario = rtps.FcstScenarioVarFinPln.toString().replaceAll("\"", "")
String strVersion = rtps.FcstVersionVarFinPln.toString().replaceAll("\"", "")
String strPeriod = rtps.PeriodVarFinPln.toString().replaceAll("\"", "")
String strYear = rtps.YearVarFinPln.toString().replaceAll("\"", "")
                
                /* Println writes a message to the Job Console */
println "Data map running for $strScenario $strVersion $strPeriod $strYear"
 
                /* Define the RULES job with name of the business rule to execute and pass in the string variables to the RTPS in the business rule */
def payload = """ {
                "jobType":"RULES", "jobName":"DataPush_TBandOther_InputToRpt_ActToFcst", "parameters":{"FcstScenarioVarFinPln":"$strScenario","FcstVersionVarFinPln":"$strVersion","PeriodVarFinPln":"$strPeriod","YearVarFinPln":"$strYear"}
}
"""
 
/* Build the json string to execute the REST job defined in the payload – update connection name and application name */ 
HttpResponse<String>  jsonResponse = operation.application
    .getConnection("Loopback_Rest")
    .post('/rest/v3/applications/FinPlan/jobs')
    .header("Content-Type", "application/json")
    .body(payload).asString();
 
                /* Monitor the REST job to completion – update connection name and application name */
ReadContext ctx = JsonPath.parse(jsonResponse.body)
def jobId = ctx.read('$.jobId')
int status = ctx.read('$.status')
 
final int IN_PROGRESS = -1
for(long delay = 50; status == IN_PROGRESS; delay = Math.min(1000, delay * 2)) {
 
                sleep(delay)
                HttpResponse<String> pingResponse = operation.application.getConnection("Loopback_Rest").get("/rest/v3/applications/FinPlan/jobs/$jobId").asString()
                status = JsonPath.parse(pingResponse.body).read('$.status')  
}    
 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s