Skip to Content

Using the incredibly useful post by Jannis Rondorf as a starting point, I wanted to write this blog post to show how IdM could access a REST API / WebService (HTTP & HTTPS) only using JAVA & JavaScript (without any custom JAVA classes or VDS); the following script should be pretty self-explanatory for the most part, but comments should hopefully make things a little clearer; please feel free to comment if you have any further doubts / questions and I will do my best to answer them:

// Main function:pushDataToAPI

function pushDataToAPI(Par) {
    importClass(Packages.java.net.HttpURLConnection);
    importClass(Packages.java.net.URL);
    importClass(Packages.java.io.DataOutputStream);
    importClass(Packages.java.io.ByteArrayOutputStream);

    var targetAPI = Par.get("TARGET_SYSTEM");
    var APIintent = "";

    var systemA_URL = "http://systemAHostNAME:1234/api/user"; 

    var systemD_CreateURL = "http://systemDHostName:1234/system_API/systemapi.svc/rest/createUser";
    var systemD_UpdateURL = "http://systemDHostName:1234/system_API/systemapi.svc/rest/updateUser";
    var systemD_Username = "systemDAPIUser";
    var systemD_Password = "systemD@APIUser1234";
    var systemD_Encoding = uToBase64(systemD_Username + ":" + systemD_Password); //encode the system D user credentials into Base64
    var systemA_Username = "systemARestAPIUser";
    var systemA_Password = "systemA@RestAPIUser1234";
    var systemA_Encoding = uToBase64(systemA_Username + ":" + systemA_Password); //encode the system A user credentials into Base64

    var logFileText = "";

    var urlString = "";


    //determine target URL based on passed in TARGET_SYSTEM parameter
    //with System D, there are two separate URLs for User CREATION and User UPDATING
    if (targetAPI == "systemA")
        urlString = systemA_URL;
    else if (targetAPI == "systemD") {
        APIintent = Par.get("API_intent");
        if (APIintent == "Create") {
            uWarning("In System D section now, going to hit CREATE API: ");
            urlString = systemD_CreateURL;
        } else if (APIintent == "Update") {
            uWarning("In System D section now, going to hit UPDATE API: ");
            urlString = systemD_UpdateURL;
        }
    }

    uWarning("FOR THIS API system: " + targetAPI);
    uWarning("determined URL: ");
    uWarning(urlString);


    //get the necessary attributes from the entry being processed currently

    var currentEntry = uGetEntryID();
    var allAttrs = uIS_GetEntry(currentEntry);
    var entFName = allAttrs.get("MX_FIRSTNAME");
    var entLName = allAttrs.get("MX_LASTNAME");
    var entUsername = allAttrs.get("MSKEYVALUE");
    var entServiceType = allAttrs.get("MX_FS_PERSONNEL_AREA");
    var entPayrollNo = allAttrs.get("MX_FS_PERSONNEL_NUMBER");
    var entEmail = allAttrs.get("MX_MAIL_PRIMARY");
    var entPhone = allAttrs.get("MX_PHONE_PRIMARY");
    var entMobile = allAttrs.get("MX_MOBILE_PRIMARY");
    var entDepartment = allAttrs.get("MX_DEPARTMENT");
    var entPrivCode = allAttrs.get("MX_FS_JOB_ID");
    var entEmpStatus = allAttrs.get("MX_FS_EMPLOYMENT_STATUS_ID");
    var entAdocode = allAttrs.get("MX_FS_ORGANIZATIONAL_UNIT_ID");
    var entOrgID = allAttrs.get("MX_DEPARTMENT");
    var entAccountingCode = allAttrs.get("MX_ACCOUNTING_NUMBER");


    //set up the message data based on the specific system; system A in this case accepts XML data via its API, while system D accepts JSON data.
    var systemA_ObjData = '<UserDataFeed xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="SystemA.API.Integration">\n<FirstName>' + entFName + '</FirstName>\n<LastName>' + entLName + '</LastName>\n<EmploymentTypeID>' + entServiceType + '</EmploymentTypeID>\n<StaffNumber>' + entPayrollNo + '</StaffNumber>\n<Adocode>' + entAdocode + '</Adocode>\n<UnitID>' + entOrgID + '</UnitID>\n<Workemail>' + entEmail + '</Workemail>\n<MilitaryTelephone>' + entPhone + '</MilitaryTelephone>\n<MobileTelephone>' + entMobile + '</MobileTelephone>\n<Username>' + entEmail + '</Username>\n<UserStatusID>' + entEmpStatus + '</UserStatusID>\n<UserType>' + entPrivCode + '</UserType>\n<Position>' + entDepartment + '</Position>\n<Employer>IDMEmployer</Employer>\n<BudgetCode>' + entAccountingCode + '</BudgetCode>\n</UserDataFeed>';

    var systemD_ObjData = '{"emailAddress" : "' + entEmail + '","firstName" : "' + entFName + '","lastName" : "' + entLName + '","customerIdentifier" : "' + entAdocode + '","roleIdentifier" : "' + entPrivCode + '"}';


    var objWithVars = '';

    //determine data to be sent to target system
    if (targetAPI == "systemA")
        objWithVars = systemA_ObjData;
    else if (targetAPI == "systemD")
        objWithVars = systemD_ObjData;

    uWarning("determined obj data: ");
    uWarning(objWithVars);

    //convert data to be sent into ByteArray
    var bytesObj = new ByteArrayOutputStream();
    bytesObj.reset();
    for (var i = 0; i < objWithVars.length; ++i) {
        bytesObj.write(objWithVars.charCodeAt(i));
    }

    var url = new URL(urlString); //create new URL based on selected target system

    var writeConn;

    writeConn = url.openConnection(); //open an HTTP connection using the selected URL

    writeConn.setDoOutput(true); //set output flag for HTTP connection to be true
    writeConn.setDoInput(true); //set input flag for HTTP connection to be true

    var verb = "POST";

    //based on selected target system, select the HTTP VERB; in this case it is either PUT if System D has to be updated, or POST for any other scenario
    if (targetAPI == "systemD" && APIintent == "Update") {
        verb = "PUT";
        writeConn.setRequestMethod(verb);
    } else if (targetAPI == "systemA" || (targetAPI == "systemD" && APIintent == "Create")) {
        verb = "POST";
        writeConn.setRequestMethod(verb);
    }

    //set up the authorization header for based on the selected target system; this section can be skipped if using an REST / WebService endpoint, 
    //that does not require authentication
    if (targetAPI == "systemD") {
        writeConn.setRequestProperty("Authorization", "Basic " + systemD_Encoding);
    } else if (targetAPI == "systemA") {
        writeConn.setRequestProperty("Authorization", "Basic " + systemA_Encoding);
    }

    //set up the content-type header based on the selected target system
    if (targetAPI == "systemD") {
        writeConn.setRequestProperty("Content-Type", "application/json");
    } else {
        writeConn.setRequestProperty("Content-Type", "application/xml");
    }

    uWarning("set request method and content type! Going to push data to API now!");

    //initiate a connection to the selected target system and then write the composed data to that system
    //response messages are then logged once the 
	try {
	    writeConn.connect();
	    var dataOS = new DataOutputStream(writeConn.getOutputStream());
	    dataOS.write(bytesObj.toByteArray(), 0, bytesObj.size());
	    dataOS.flush();
	    dataOS.close();
	} catch (idmerr) {
	    uWarning("Encountered error while trying to push data to API: ");
	    uWarning(idmerr);
	    uWarning(idmerr.message);
	    uSkip(1);
	}

        var responseCode = writeConn.getResponseCode();
        var responseMsg = writeConn.getResponseMessage();

	uWarning("Response MSG for the " + verb + ": " + responseMsg);
	uWarning("Response CODE for the " + verb + ": " + responseCode);
	uWarning("Header FIELD 0 for the " + verb + ": " + writeConn.getHeaderField(0));


    //if a response code other than 200 or 201 is encountered, that means an error has occurred and this will then be written to an external log file
    //if logging to a file is not required this section can be removed.
    if (writeConn.getResponseCode() !== 200 && writeConn.getResponseCode() !== 201) {
        logFileText += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r\n";
        logFileText += "For SYSTEM " + targetAPI + "\r\n";
        logFileText += "hitting API URL: " + urlString + "\r\n";
        logFileText += "with this payload:\n " + objWithVars + "\r\n";
        logFileText += "*************************************\r\n";
        logFileText += "THIS IS THE Header FIELD 0:\n " + writeConn.getHeaderField(0) + "\r\n";
        logFileText += "THIS IS THE RESULT CODE:\n " + writeConn.getResponseCode() + "\r\n";
        logFileText += "THIS IS THE RESULT MESSAGE:\n " + writeConn.getResponseMessage() + "\r\n";
        logFileText += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r\n";
        uToFile("C:\\IDM_ErrorFile.txt", logFileText, true);
    }

    //finally disconnect the HTTP connection after the data has been pushed to the REST API / WebService
    writeConn.disconnect();

}

NOTE: HTTP & HTTPS connections can both be accessed using the HTTPUrlConnection JAVA Class; in the case of an HTTPS API, you will need to import the SSL certificate of the secured target API web server, into the JAVA Keystore (following the IDM documentation:Exporting and Installing the SSL Certificate – SAP Identity Management Installation and Update Guide – SAP Library); if the SSL certificate is not imported you will encounter an SSL handshake error, when trying to access the secured HTTPS REST API / WebService.

Using similar logic / concepts you can retrieve data from a REST API / WebService instead of pushing data to it (as demonstrated in the above example).

I hope this helps give you a better understanding of how you can access a REST API directly from SAP IDM, simply using JAVA / JavaScript, as well as the different use cases this can be applied to.

To report this post you need to login first.

2 Comments

You must be Logged on to comment or reply to a post.

Leave a Reply