Skip to Content

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

/wp-content/uploads/2016/04/1_920414.png

Step Type Description
Integration Flow Trigger
  • The Integration Flow is triggered using a IDoc Sender Channel.
  • The authentication mode is set to Basic Authentication.
Content Modifer
  • Content Modifier sets the Header properties SAP_ApplicationID, SAP_Sender, SAP_Receiver
  • SAP_ApplicationID is set to the IDoc number XPath to enable search for the Interface with the IDoc Number
  • SAP_Sender is set to SNDPRN XPath to enable set Sending System Details
  • SAP_Receiver is set to RCVPRN XPath to enable set Receiver System Details
  • This is an optional step and can be skipped.
Mapping
  • The Message Mapping to Map the Source IDoc to the UPSERT Webservice call is triggered.
  • This blog does not go into the details of this mapping and this should be covered in the Pre-Requiste section of the Part1 of this Blog series
Content Modifier
  • Set the Property – sessionID, sessionURL, sessionTime.
  • These Properties are read from the Global Variables persisted in the IntegrationFlow#1- Login.
  • Setting these properties in this step enables these to be accessible as local variables within the Integration Flow
Script
  • The script checks if the sessionID is valid. SalesForce sessionIDs are valid for 2 hours from the time the Login is made.
  • This Groovy script checks the if currentTime is within sessionTime+2 Hours
    • If yes, property sessionValid is set to True
    • If no, property sessionValid is set to False
  • In summary, this Script checks if the session continues to be valid and sets a Flag accordingly.
Gateway
  • If Session InValid -> Branch 1
  • If Session Valid -> Branch 2 (Default Branch)

SessionInValid –

Branch 1

Request Reply

  • Make a SOAP Call to the Integration Flow#1 Login
  • This Request Reply step triggers the call to the Integration Flow #1, if the session is Invalid and a Login call has to be made to get a new sessionID.
Content Modifier
  • Set the Property – sessionID, sessionURL, sessionTime.
  • These Properties are read from the Global Variables persisted in the IntegrationFlow#1- Login.
  • Setting these properties in this step enables these to be accessible as local variables within the Integration Flow
Script
  • Add sessionID to the SOAP Header
  • Perform certain XML Namespace Manipulations – Reasons for this are as described in the Prerequisite documents of Blog 1 of this series.
Request – Reply
  • Make the SOAP call to SalesForce to perform Upsert operation

 

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

/wp-content/uploads/2016/04/2_921393.png

Mapping

Mapping from the Source IDoc to the SFDC Upsert Request. The details of the mapping are not discussed in this blog.

/wp-content/uploads/2016/04/3_921394.png

Content Modifier

Content Modifier enables to set the Property sessionID,sessionURL,sessionTime. The values for these properties are read from their corresponding Global Variables.

/wp-content/uploads/2016/04/4_921416.png

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

/wp-content/uploads/2016/04/5_921417.png

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.

/wp-content/uploads/2016/04/6_921418.png

/wp-content/uploads/2016/04/7_921419.png

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.

/wp-content/uploads/2016/04/4_921416.png

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="http://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<SoapHeader>();
   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.

/wp-content/uploads/2016/04/8_921421.png

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 )

/wp-content/uploads/2016/04/9_921647.png

  • 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.

/wp-content/uploads/2016/04/11_921428.png

Global Data Store Updated via the Login Integration Flow

/wp-content/uploads/2016/04/16_921444.png

 

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.

/wp-content/uploads/2016/04/12_921435.png

/wp-content/uploads/2016/04/13_921437.png

Logs Show the sessionID Status as per the Groovy Script

 

/wp-content/uploads/2016/04/15_921439.png

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!

To report this post you need to login first.

9 Comments

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

  1. Vijay Kumar KVN

    Thanks bhavesh…before this blog i got stucked up at creation of the soap headers…. now i will understand from your blog and i will try … Regards, Vijay

    (0) 
  2. Bhavesh Kantilal Post author

    Hello Mohammed Amine,

     

    Can you explain more in terms of what you mean by a UPDATE operation?

    In this blog, i have illustrated a case where the data from SAP is replicated to SFDC using UPSERT operation.

     

    Do you mean to say a case where HCI Queries SFDC, pushes the data to SAP and then updates back to SFDC? Technically its just another iFlow. Is there some challenge you are facing there?

     

    Regards,

    Bhavesh

    (0) 
    1. Mohammed Amine FRAYJIA

      Yes Mr Bhavesh this is almost what I need to do. Let me explain more :

      I nees to achieve two main steps :

       

      1 – Getting opportunities from Salesforce and send them to SAP ByD

      2 – Update the status for those opportunities in Salesforce


      But for testing purposes I am dealing with Account instead of Opportunity, the query is working fine, I am selecting the account Name and I want to change it in HCI and  update it back to Salesforce.


      So I will need your help to figure out who can I update the account name that I selected previously.


      I am using the enterprise WSDL which contain an update operation I have no idea about what is required before calling this update operation via a request-reply .

       

      Thanks,

      BR.

      Mohamed Amine

      (0) 
  3. Mohammed Amine FRAYJIA

    Dear Bhavesh, I am currently reproducing your flow, and I am getting an error after trying to login again, is it a problem with the first login flow ?


    This is the error :

     

     

    Processing exchange ID-vsa1129456-od-sap-biz-56095-1462637259951-477-6 in cxf:bean:HCI_Login_{

    Error               = org.apache.camel.InvalidPayloadException: No body available of type: org.apache.camel.component.cxf.CxfPayload on: Message: [Body is not logged]. Caused by: No type converter available to convert from type: null to the required type: org.apache.camel.component.cxf.CxfPayload with value null. Exchange[ID-vsa1129456-od-sap-biz-56095-1462637259951-477-6][Message: [Body is not logged]]. Caused by: [org.apache.camel.NoTypeConversionAvailableException – No type converter available to convert from type: null to the required type: org.apache.camel.component.cxf.CxfPayload with value null], cause: org.apache.camel.NoTypeConversionAvailableException: No type converter available to convert from type: null to the required type: org.apache.camel.component.cxf.CxfPayload with value null

     

    Any idea about this error ?

    Thanks.

    BR.

    Mohamed Amine.

    (0) 
    1. Bhavesh Kantilal Post author

      Hello Mohammed Amine,

      The error seems to be because you have triggered a Login call as your session ID has expired and the Login Integration flow has failed.

      I would suggest you raise this in the SCN Forum as this could be a long topic of discussion but for a quick check this is what I would do,

       

      – Check which step is failing by enabling Trace.

      – Check what is the input to that step and if the previous step provided the right input.

      – I think somewhere the contentModifer step is incorrect where the Body is set and that is causing the issue.

       

      Regards,
      Bhavesh

      (0) 
      1. Mohammed Amine FRAYJIA

        It was because there was no message inside the body payload, I added some content and I got a new error :

        Cxf.EndpointAddress = https://XXXX/cxf/SF/Login

                                                                                                                              Error               = Inbound processing in endpoint at https://XXXX/cxf/SF/Login failed with message “Fault:Could not send Message.”, caused by “HTTPException:HTTP response ‘401: Unauthorized’ when communicating with https://XXXX/cxf/SF/Login”

         

        I added the tenant certificate to the systems.jks. But still getting the same error Unauthorized’ when communicating with https://XXXX/cxf/SF/Login

        (0) 

Leave a Reply