EPM GROOVY – Pushing Web Form Data Updates Across Multiple Instances

UPDATE : Cross Platform SmartPush Data push is available in the DataMaps

The purpose is to push data using a webform attached business rule that captures the edited rows and pushes data to a different EPBCS instance. 

Within the application, the calculation manager has multiple options, including data map, smart push, and DataGridBuilder. The REST API addition to the existing Calculation Manager library is already helpful in so many ways. I have covered a few examples in the previous posts. This one is different and useful for people who manage applications in multiple instances. 


Import data slice is a well-known feature that has been around here for many years. But what we do differently this time is to get the data slice from the user web form itself using business rules. The trick is to convert the DataGrid object to JSON Grid, which is supported in REST calls. This is a grid-based data import, so by default this option doesn’t allow more than 500K cells submission. It will definitely fail to import, as it’s the same as smart push. So this option is only meant for a small set of instant data pushes between instances. Also, the user needs to have access to the target intersections, and the intersections must be valid for data submission.

Get Web Form Components

I am going to get POV, columns, and row components along with the data. We can filter the rows based on preconditions. I am going to choose only the edited metrics from the webform. If the target application has additional dimensions or needs to be mapped to different members, we can specify all of this in the calculation manager itself.

Cube cube = operation.cube
//get POV members
List<List<String>> povMembers = operation.grid.pov.collect{[it.MbrName]}

//get column members
List<List<String>> columnMembers = operation.grid.columns*.collect{DataGrid.HeaderCell it -> it.MbrName}

//get row members along with data
def rowHeader = []
List<DataGrid.Row> gridRows = operation.grid.rows 
gridRows.each { curRow ->

        //check if any one of the cell in a row is edited
	if(curRow.data.any{it.edited}) {
		List<List<String>> rowMembers = curRow.headers*.collect{DataGrid.HeaderCell mbr -> mbr.MbrName}	
		List<Double> rowData = curRow.getData().collect{it.data}
		def rows = [:]
		rows['headers'] = rowMembers.flatten()
		rows['data'] = rowData
		rowHeader << (rows)

Convert DataGrid to JSON Grid

Since we have the JSON class added into the calculation manager, it is easier to generate JSON objects from a HashMap. I shall populate the items into a HashMap and let the JSON builder worry about all the conversions. The JSON Grid is case-sensitive, so it is best to follow the same conversions as provided in the documentation.

def jsonDataGrid = [
                "dataGrid" : [
                    "pov" : povMembers.flatten(),
                    "columns" :columnMembers,

Set Up the connection

This is an external rest connection setup. So it is important to follow “domain.username” in the username section in the connections window to avoid authentication issues. The connection needs to be set up in the source instance.

Call REST Services

The rest of the calls can be triggered if any of the rows are edited.

if(rowHeader) {
	HttpResponse<String> jsonResponse = operation.application.getConnection("targetInstance").post("/HyperionPlanning/rest/v3/applications/MyApp/plantypes/PlanType1/importdataslice")
									.header("Content-Type", "application/json")
    println jsonResponse.body

Finally, Execution

Job Console output:

I don’t recommend this option for larger data volume pushes. I have validated this option for just one row. It is faster for one row, but I cannot comment on the performance when the volume is higher. Please try it at your own risk.