HCI -Integrating SalesForce (SFDC) using HCI -Part 2
Background
In Part 1 of this blog series, a Login Integration Flow was created that persisted the sessionID, serverURL and sessionTime to the Global Variables of HCI.
- How is this Integration Flow#1 used when the IDoc from SAP arrives to HCI?
- How can a Global Variable be read from the HCI DataStore?
- How easy is it to add SOAP Headers to your SOAP Message?
This blog covers this and the end to end flow. Read on!
Update#1: Currently ( As of Apr 12, 2016 ) HCI does not support the ability to set the SOAP URL Dynamically in the SOAP Receiver Adapter. Hence, at this moment, while the SOAP URL is persisted into the Global Variables, this is not used anywhere. The list of parameters supported Dynamically is listed here : HCI Dynamic Parameters
Nov 3, 2016 – The limitation described is no longer applicable. You can set the URL Dynamically as described in this blog : Dynamic address in the SOAP receiver adapter of HANA Cloud Platform, Integration Services by M.Jaspers
Integration Flow#2 – Material Master Replication Process
ProcessFlow
Step Type | Description |
---|---|
Integration Flow Trigger |
|
Content Modifer |
|
Mapping |
|
Content Modifier |
|
Script |
|
Gateway |
|
SessionInValid – Branch 1 Request Reply |
|
Content Modifier |
|
Script |
|
Request – Reply |
|
Content Modifier
Set the Headers to enable monitoring with the corresponding IDoc Headers. The documentation on this can be read in the blog: End2End monitoring of HCI message flow in Standard Content – Made easy
Mapping
Mapping from the Source IDoc to the SFDC Upsert Request. The details of the mapping are not discussed in this blog.
Content Modifier
Content Modifier enables to set the Property sessionID,sessionURL,sessionTime. The values for these properties are read from their corresponding Global Variables.
Script
The below script is used to validate if the session is valid. If session is Valid, property sessionValid is set to “True” else set to “False”
import com.sap.gateway.ip.core.customdev.util.Message; import java.util.HashMap; import java.util.Date; import java.text.SimpleDateFormat; def Message processData(Message message) { def messageLog = messageLogFactory.getMessageLog(message); def propertyMap = message.getProperties() //Read sessionTime from the Properties String sessionTime = propertyMap.get("sessionTime"); //Set a Log Message for Monitoring purporses messageLog.setStringProperty("sessionTime ", sessionTime); // Convert sessionTime to a Calendar Date Calendar cal = Calendar.getInstance(); SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); cal.setTime(sdf.parse(sessionTime)); // Add 2 Hours to sessionTime Calendar cal1 = Calendar.getInstance(); SimpleDateFormat sdf1 = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); cal1.setTime(sdf1.parse(sessionTime)); cal1.add(Calendar.HOUR_OF_DAY, 2); // Get Current Time SimpleDateFormat sdfDate = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");//dd/MM/yyyy Date now = new Date(); String sessionValid = ""; // Validate if session is Valid if(now.before(cal1.getTime())){ sessionValid = "true"; }else{ sessionValid = "false"; } message.setProperty("sessionValid",sessionValid); messageLog.setStringProperty("sessionValid ", sessionValid); return message; }
Parallel MultiCast & Gateway
Parallel MultiCast is used to enable have a Join Step to merge the multiple branches of the Gateway Step. If you would like to understand these step types further would suggest reading the blog : Multicast Pattern in Integration Flows (HCI-PI)
Gateway Properties are as below
- If sessionValid = ‘False’ -> Make a Request/Reply call to HCI Integration Flow #1 – Join Step
- If sessionValid = ‘True’ -> Default Branch as no call to SFDC for Login is required – Join Step
Request Reply
As mentioned previously, this Request Reply step uses the SOAP Adapter to make a call back to Integration Flow#1.
The SOAP Adapter treats this like any other Webservice and the Proxy-Type used has been Set to “Internet”.
At this moment, I am not aware of any other means to trigger an Integration Flow of HCI and hence this approach has been documented.It would be great if a inbuilt feature is provided to do this to avoid traffic over the internet.
Content Modifier
This content modifier step performs the same tasks as one of the previous content modifier steps,i.e, enables to set the Property sessionID, sessionURL, sessionTime. The values for these properties are read from their corresponding Global Variables.
Script
This script is used to insert SOAP Headers into your Message. In this case, we insert the sessionID into the SOAP Header.
Note: This script also performs some rudimentary XMLNamespace manipulations for SFDC to address the WSDL Incompatibilities into your PI Graphical Mapping editor. There are better ways to do this including a XSLT / Parsing Technique. This blog does not delve into the details of the same.
import com.sap.gateway.ip.core.customdev.util.Message; import java.util.ArrayList; import java.util.List; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.cxf.binding.soap.SoapHeader; import org.w3c.dom.Document; import org.w3c.dom.Element; import com.sap.it.api.ITApiFactory; import com.sap.it.api.securestore.SecureStoreService; import com.sap.it.api.securestore.UserCredential; import groovy.util.XmlSlurper; def Message processData(Message message) { def body = message.getBody(); def messageLog = messageLogFactory.getMessageLog(message); // Read SessionID from the Property def propertyMap = message.getProperties() String sessionID = propertyMap.get("sessionID"); // Perform certain XMLNamespace manipulations. Note this is a very rudimentary mode of performing the same. // An XSLT or a Parser are better modes to do the same. String payload = message.getBody(java.lang.String); payload = payload.replaceAll('type','xsi:type'); payload = payload.replaceAll('xmlns:ns0="urn:enterprise.soap.sforce.com"','xmlns:ns0="urn:enterprise.soap.sforce.com" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"'); payload = payload.replaceAll('xsi:type="Product2"','xsi:type="urn1:Product2"'); message.setBody(payload); // Set SOAP Heeader sessionID DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); dbf.setIgnoringElementContentWhitespace(true); dbf.setValidating(false); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.newDocument(); Element authHeader = doc.createElementNS("urn:enterprise.soap.sforce.com", "SessionHeader"); doc.appendChild(authHeader); Element clientId = doc.createElement("sessionId"); clientId.setTextContent(sessionID); authHeader.appendChild(clientId); SoapHeader header = new SoapHeader(new QName(authHeader.getNamespaceURI(), authHeader.getLocalName()), authHeader); List headersList = new ArrayList(); headersList.add(header); message.setHeader("org.apache.cxf.headers.Header.list", headersList); messageLog.setStringProperty("SessionID ", sessionID); return message; }
Request Reply
Now that the SOAP Message is formed with the correct SessionID in the SOAP Header, the request reply is aimed at making the SOAP Call to SFDC to perform the corresponding operation on SFDC. Unlike in the PI world, where a Do Not Use SOAP Envelope mode is required, so such mode is required in HCI as HCI natively provides a mode to manipulate the SOAP Header.
Testing Your Flow
- Prior to testing this Integration Flow, make sure that the Integration Flow#1 Login has been triggered atleast once manually through SOAP UI. Reason : This Integration Flow assumes that the Global Variables sessionID, sessionURL and sessionTime exist in the SAP Data Store.
- Trigger the IDoc from SAP.
Results
- IDoc Triggered at 8:53:56 AM, Processing Time ~ 6 Seconds
- This Integration Flow makes the Call to the Login Integration Flow.
- The Logs also show the call to the Login Integration Flow ( Once )
- IDoc’s triggered at 8:53:58 and 8:54:00, Procesing Time ~ 1 Second
- This Integration Flow re-uses the SessionID as the sessionID is valid.
Global Data Store Updated via the Login Integration Flow
Additional Details
- Search using IDoc# works as required. Note as the variable was declared as a Integer only Number is to be used.
- Likewise if variables is declared as a String, the same needs to be appended with zeroes or wild card prefix is to be used.
Logs Show the sessionID Status as per the Groovy Script
Final Note
The above 2 blogs show a means to implement a Integration with SFDC. Like in the PI world, there are multiple design options for this integration requirement. The idea behind this blog was not to delve into the various other options but show users how the most common approach used for persistence of sessionID’s can be implemented using HCI.
Other patterns / models can be added into the comment sections!
New NetWeaver Information at SAP.com
Very Helpfull