Executing BIP Report from Oracle EPM using Groovy

Executing BIP Report via REST in Oracle Fusion

Continuing from our previous post Exploring ESS Job Execution via REST using Groovy , where we demonstrated how to execute an ESS job in Oracle EPM using Groovy, today we’ll explore how to execute a BIP (BI Publisher) report directly using a similar approach.

Note: This method comes with a limitation — the BIP report must complete execution within 5 minutes, or it will result in a timeout error. This post is intended for educational purposes and may be useful in scenarios where the report logic is not too complex and can finish within the time limit.

Key Differences

The overall structure of the code remains largely the same as in the previous example. However, the key difference lies in how we invoke the BIP report. Instead of a standard ESS job, we use a generic ESS job in Oracle Fusion called FinOutboundProcess. We pass the BIP report name and its required parameters as part of the request.

Sample Code


HttpResponse<String> EssJobResponse = operation.application.getConnection("OracleERP")
    .post("/fscmRestApi/resources/latest/erpintegrations")
    .header("Content-Type", "application/json")
    .body("""
    {
        "OperationName": "submitESSJobRequest",
        "JobPackageName": "/oracle/apps/ess/financials/commonModules/shared/common/outbound", 
        "JobDefName": "FinOutboundProcess",
        "ESSParameters": "#Null,/Custom/Human Capital Management/Payroll/Restricted/Salary Details Report.xdo,BIPONLY,#Null,EPMDataManagement,02-28-2025"
    }
    """)
    .asString();

This call mirrors what you would typically see in Oracle Data Management job logs when a BIP report is executed directly.

Final Thoughts

Aside from the change in the job definition and parameters, the rest of the code remains the same as discussed in the previous post . This approach can be a handy addition to your toolkit when working with Oracle Fusion and EPM integrations.

Entire Code



/* RTPS:  */

import java.util.Base64
import groovy.json.JsonSlurper
import java.util.zip.ZipInputStream
import java.util.zip.ZipEntry
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream

String START_DATE = "2025-03-01"
String END_DATE = "2025-03-31"
   
HttpResponse EssJobResponse = operation.application.getConnection("OracleERP")
    .post("/fscmRestApi/resources/latest/erpintegrations")
    .header("Content-Type", "application/json")
    .body("""
    {
        "OperationName": "submitESSJobRequest",
        "JobPackageName": "/oracle/apps/ess/financials/commonModules/shared/common/outbound", 
        "JobDefName": "FinOutboundProcess",
        "ESSParameters": "#Null,/Custom/Human Capital Management/Payroll/Restricted/Salary Details Report.xdo,BIPONLY,#Null,EPMDataManagement,02-28-2025"   	
    }
    """)
    .asString();
def responseBody = EssJobResponse.getBody()
def parsedResponse = new JsonSlurper().parseText(responseBody)
def reqstId = parsedResponse["ReqstId"] as String

println("ESS Job submitted successfully and the Request id is $reqstId")
  
if (!reqstId) {
	println "Failed to retrieve ReqstId from ESS job submission response."
    println "Response: $responseBody"
    return
}

String getJobStatus(String connectionName, String reqstId) {
	def payload = """
    {
    	"OperationName": "getESSJobStatus",
        "ReqstId": "$reqstId"
    }
    """
	HttpResponse jobResponse = operation.application.getConnection(connectionName)
    	.post("/fscmRestApi/resources/11.13.18.05/erpintegrations")
        .header("Content-Type", "application/json")
        .body(payload)
        .asString()
        
	String responseText = jobResponse.getBody()
    try {
    	def parsed = new JsonSlurper().parseText(responseText)
        return parsed["RequestStatus"] ?: "UNKNOWN"
    } 	catch (Exception e) {
    	println("Error parsing job status response: ${e.message}")
        return "UNKNOWN"
    }
}

int maxRetries = 100
int retries = 0
String status = "RUNNING"

while ((status == "RUNNING" || status == "WAIT" || status == "READY") && retries < maxRetries) {
	println("Polling attempt ${retries + 1} for ESS Job ID $reqstId...")
    status = getJobStatus("OracleERP", reqstId)
    println("Current job status: $status")
    println()
    if (status == "RUNNING") {
    	sleep(2000*30*2) // Wait 2 minutes before next poll
       }
       retries++
}

if (status == "SUCCEEDED") {
	println("ESS Job $reqstId completed successfully.")
} else if (status == "FAILED") {
	println("ESS Job $reqstId failed.")
} else {
	println("ESS Job $reqstId did not complete within the expected time. Final status: $status")
}

Map decodeAndExtractBase64Zip(String base64String) {
    def extractedFiles = [:] as Map

    try {
        byte[] zipBytes = Base64.decoder.decode(base64String)
        ByteArrayInputStream byteStream = new ByteArrayInputStream(zipBytes)
        ZipInputStream zipStream = new ZipInputStream(byteStream)

        ZipEntry entry
        while ((entry = zipStream.nextEntry) != null) {
            ByteArrayOutputStream output = new ByteArrayOutputStream()
            byte[] buffer = new byte[1024]
            int len
            while ((len = zipStream.read(buffer)) > 0) {
                output.write(buffer, 0, len)
            }
            extractedFiles[entry.name] = output.toByteArray()
            zipStream.closeEntry()
        }

        zipStream.close()
    } catch (Exception e) {
        println "Error during decoding or extraction: ${e.message}"
    }

    return extractedFiles
}

HttpResponse erpResponse = operation.application.getConnection("OracleERP")
.post("fscmRestApi/resources/11.13.18.05/erpintegrations")
.header("Content-Type", "application/json")
.body("""
{
  "OperationName": "downloadESSJobExecutionDetails",
  "ReqstId": "$reqstId",
  "FileType": "ALL"
}
""")
.asString()


def responseBodyERP = erpResponse.getBody()
def parsedJson = new JsonSlurper().parseText(responseBodyERP)
def base64Content = parsedJson["DocumentContent"] as String


if (!base64Content) {
    println("No document content found in the response.")
    return
}

def zipBytes = Base64.decoder.decode(base64Content)
def zipStream = new ZipInputStream(new ByteArrayInputStream(zipBytes))
ZipEntry entry = zipStream.nextEntry
entry = zipStream.nextEntry
if (entry == null) {
	println "ZIP file is empty before upload."
    return
} else {
	println ("Found entry: ${entry.name}")
}

Map files = decodeAndExtractBase64Zip(base64Content)

try{


files.each { name, content ->
    try {
       if(name == "$entry"){
       	byte[] contentBytes = (byte[]) content
        String text = new String(contentBytes, "UTF-8")
        println "File: $name"
        HttpResponse apendFile = operation.application.getConnection("Salary")
.post("/interop/rest/11.1.2.3.600/applicationsnapshots/$name/contents")
.header("Content-Type", "application/octet-stream")
.body(text)
.asString()

        }
    } catch (Exception e) {
        println "Error processing file $name - ${e.message}"
    }
}
} catch (Exception e) {
        println "Error processing file ${e.message}"
    }



Comments