Friday, 4 May 2018

Clearing/Resetting the Headers Parameters in SAP HCI/CPI

To clear the headers from the outgoing message request.

On many occasions we have a business scenario where, we need to do multiple lookup calls to an external system with some message transformation and then make some external HTTP call to post the transformed message.

One of business requirement was wherein we had to look up from S/4 HANA system and subsequently post the transformed message to an external third party system using HTTP Post(method).

While we were making individual calls to the third party system, it was working perfectly fine but once we joined all the pieces and completed the i-flow, we were unable to post the message resulting in error 406.

Hence we decided to log all the headers and see if there were any additional headers which would have been carried from the previous SOAP call to S/4 HANA.import com.sap.gateway.ip.core.customdev.util.Message; import java.util.HashMap; def Message processData(Message message) { def headers = message.getHeaders() def messageLog = messageLogFactory.getMessageLog(message) for (header in headers) { messageLog.setStringProperty("header." + header.getKey().toString(), header.getValue().toString()) } return message; }

Above code helped us to get the list of header values from the current message.

On further analysis we could understand that, there could be various reasons why the message header could get appended with different values which might not be relevant in preceding calls. After reading the below paragraph from standard documentation we had a clue of possible error.Note that data written to the message header during a processing step (for example, in a Content Modifier or Script step) will also be part of the outbound message addressed to a receiver system (whereas properties will remain within the integration flow and will not be handed over to receivers). Because of this, it is important to consider the following header size restriction if you are using an HTTP-based receiver adapter: If the message header exceeds a certain value, the receiver may not be able to accept the inbound call (this applies to all HTTP-based receiver adapters). The limiting value depends on the characteristics of the receiver system, but typically ranges between 4 and 16 KB. To overcome this issue, you can use a subsequent Content Modifier step to delete all headers that are not supposed to be part of the outbound message.

Now this clearly states that there could be certain irrelevant headers which could be causing a problem.

If we retain some relevant headers and delete the rest we could have three different use cases:
Delete specific header values
Delete all the header values
Delete all the headers except masking a few.

So the next target was to achieve these use cases. Please follow the steps below
Select Content Modifier step before the HTTP call.
Select Message Header section
Click Add button
Select Delete from the Drop down.


Press on Select Button under Column Name which will give you a pop up




Now we have three options to handle the deletion of the headers:
Delete specific header values: In this case we can select the first option Header and mention all the header needs to be deleted. We could add ‘n’ number of header variables with the Action as delete and mention the Header to be deleted.
Delete all the header values: In case we had to delete all the headers we could select the Expression instead of Header. This would clear all the headers before the subsequent calls.

Delete all the headers except masking few: And finally if we want to mask few we could mention them under Exclude with wildcard character.




Thursday, 8 March 2018

Setting SOAP Headers in SAP HCI


You can use Groovy programming language (Groovy script) to set SOAP headers.

The following example shows a SOAP message with a SOAP header.
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Header>
       <AuthHeader soap:actor="actor_test" soap:mustUnderstand="1" xmlns="http://www.Test.com/">
          <ClientId>username</ClientId>mustUnderstand 
          <Password>password</Password>
       </AuthHeader>
   </soap:Header>
   <soap:Body>
      <test:TestMessage xmlns:test="http://hci.sap.com/ifl/test">
         <MessageContent>customer1</MessageContent>
      </test:TestMessage>
   </soap:Body>
</soap:Envelope>
To set such a SOAP header, use the following script.
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;

def Message processData(Message message) {

   // First fetch user name and password which must be entered into the SOAP header from the secure store service.
   // This is not necessary if your SOAP header does not require data from the secure store service.
   def service = ITApiFactory.getApi(SecureStoreService.class, null);
   def credential = service.getUserCredential("partner1_credential_alias");
   if (credential == null){
      throw new IllegalStateException("No credential found for alias 'partner1_credential_alias'");
   }
   String userName = credential.getUsername();
   String password = new String(credential.getPassword());

   // Create Soap Header as DOM Element;  the attributes "actor" and "mustUnderstand" must not be added;
   // these attributes can be added later see below.
   // The following lines create the DOM Element.
   //<AuthHeader xmlns=http://www.Test.com/><ClientId>"+userName+"</ClientId><Password>"+password+"</Password></AuthHeader>"
   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("http://www.Test.com/", "AuthHeader");
   doc.appendChild(authHeader);
   Element clientId = doc.createElementNS("http://www.Test.com/", "ClientId");
   clientId.setTextContent(userName);
   authHeader.appendChild(clientId);
   Element passwordEl = doc.createElementNS("http://www.Test.com/", "Password");
   passwordEl.setTextContent(password);
   authHeader.appendChild(passwordEl);

   // Create SOAP header instance.
   SoapHeader header = new SoapHeader(new QName(authHeader.getNamespaceURI(), authHeader.getLocalName()), authHeader);
   header.setActor("actor_test");
   header.setMustUnderstand(true);

   // Add the SOAP header to the header list and set the list to the message header "org.apache.cxf.headers.Header.list".
   List  headersList  = new ArrayList<SoapHeader>();
   headersList.add(header);
   message.setHeader("org.apache.cxf.headers.Header.list", headersList);
   
   return message;
}



Monday, 19 February 2018

Add header/property values in the message mapping in SAP HCI

Mapping step won’t replace the headers and Properties directly in runtime. As ${header.H1} will not be replaced with value of H1 directly, you need to write CustomFunction( UDF in SAP PI terminology) like below and call those in Message Mapping.

If you are using WriteVariable select the type as Property and set the value for that, later call it in mapping using below script.


If you are using Content Modifier, set the Property and later call it using below script as shown.


Content modifier: (used xpath variable for Status)




In mapping, pass the input as the value maintained in the content modifier(used Status here):



Use the below groovy script and pass the constant values as Status here, no change in the below code, you can directly use it.

import com.sap.it.api.mapping.*

def String getProperty(String propertyName,MappingContext context)

{
  String PropertyValue= context.getProperty(propertyName);

  PropertyValue= PropertyValue.toString();

  return PropertyValue;

}
Below is the data received after the mapping for Status as Success:



Let me know in comments if any issues.

Happy Learning!!!



Wednesday, 14 February 2018

WS-Security Configuration in SAP HCI(CPI)

In the request wsdl we do not have the header structure, as this need to be enabled the security by WS security. We will see how we are going to add the ws security login details in header.
When trying to hit directly without HCI, we can see the request as:



Added WS-security in SOAP UI:


But when we are doing in the HCI, don’t use XSLT mapping and Groovy Script as that might not work. 

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:cli="url" xmlns:com="url" xmlns:cli1="url">
   <soapenv:Header>
   <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" >
            <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-FqmwqrccDFGWEwe">
                <wsse:Username>ihub</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">zrsdgffds32eef</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
        </soapenv:Header>  
         <soapenv:Body>
            <xsl:copy-of select="*"/>   
         </soapenv:Body>    
              </soapenv:Envelope>    
</xsl:template>
</xsl:stylesheet>


As the above xslt code not working, that adding the header is displayed in body on next step.now ws-security can't be achieved using XSLT.  So enable it in the channel as shown below.

Add the login details in the deployed artifacts before configuring channel.




Happy Learning!!!



Add session ID in SOAP header at the message payload

Handling session in the SOAP header at request payload.

Login request and get the session ID as response.

Received Session Id has to be added in the header as below.

This is displayed in soap UI but when receiving to HCI it receives only body data, at that time header need to be added by below script.

Groovy Script:

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) {

   // To get a session ID
   def propertyMap = message.getProperties()
   String sessionID = propertyMap.get("sessionID");
   
   // To add the header to the actual data
   // The following lines create the DOM Element.
   //<CventSessionHeader xmlns=http://www.Test.com/><CventSessionValue>"+sessionID+"</CventSessionValue></CventSessionHeader>
   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("http://xxx/2006-11", "CventSessionHeader");
   doc.appendChild(authHeader);
   Element cventSessionValue = doc.createElementNS("http://xxx/2006-11", "CventSessionValue");
   cventSessionValue.setTextContent(sessionID);
   authHeader.appendChild(cventSessionValue);
 
   // Create SOAP header instance.
   SoapHeader header = new SoapHeader(new QName(authHeader.getNamespaceURI(), authHeader.getLocalName()), authHeader);


   // Add the SOAP header to the header list and set the list to the message header "org.apache.cxf.headers.Header.list".
   List  headersList  = new ArrayList<SoapHeader>();
   headersList.add(header);
   message.setHeader("org.apache.cxf.headers.Header.list", headersList);
  
   return message;
}

After that the operation call is performed like create, update event etc..

Happy Learning!!!





Send multiple different messages to same receiver and vice versa

There is a several case we come across for sending the different messages to same receiver and vice versa. We will look across the two cases:
1.       Same messages to different receivers




2.       Different messages to same receiver: We have different login account details in same message added in the content modifier, in which this need to hit the same system and create the registration. Then return back the response (reg id) that need to be sent to same system as different registration message.

     Login Input payload:

<ns:Account xmlns:ns="http://api.cvent.com/2006-11" >
<ns:AccountDetails>
<ns:Login>
         <ns:AccountNumber>AU001</ns:AccountNumber>
         <!--Optional:-->
         <ns:UserName>AUapi001</ns:UserName>
         <!--Optional:-->
         <ns:Password>wqr32456</ns:Password>
</ns:Login>
</ns:AccountDetails>
<ns:AccountDetails>
<ns:Login>
         <ns:AccountNumber>SG001</ns:AccountNumber>
         <!--Optional:-->
         <ns:UserName>SGapi001</ns:UserName>
         <!--Optional:-->
         <ns:Password>wert12345</ns:Password>
</ns:Login>
 </ns:AccountDetails>
      </ns:Account>


Splitter splits the different login and the send the login details one by one and create the session id.


From that session id, the process call is called to create registration and give back the response to the sender system. It appears as different registration id in source system.


Happy Learning!!!



Issues facing in SAP HCI (CPI)

In HCI iflow, all the routing conditions are met but the message is not reaching C4C. Also it is showing completed status in HCI.

Make sure in we20 port settings content type is set as Text/XML instead of Application/x.sap.idoc.

While replicating from ERP to Cloud for Customer using HCI system, all outbound idocs in ERP are failing with the following error
“No IDoc saved in target system (SOAP HTTP)”

Above error means SOAP application processing was started in the target system i.e in HCI system. However, errors occurred in the target system due to unknown reason, which means that IDocs cannot be saved in ERP. Hence for more details about failure please check in target systems error log i.e. HCI

When sending message from soapUI to the C4C the message fails in Cloud for Customer with error message
“SRT: Plain SOAP: Reliable messaging (RM) configured, but no Messaging ID and no WSRM assertion provided

Make sure the protocol defined in the Communication System of Cloud for Customer should be selected as Web Services. Also, make sure end point URL to which you are sending request from soapUI or via any middleware into C4C inbound service then it should have MessageID at the end as shown below.

e.g. https://<host>:<port>/sap/bc/srt/scs/sap/businesspartnererpreplicationi?MessageId=FA163ED10E711EE696DE10B08BF81EED

In case if you are sending data to SAP C4C using SOAPUI make sure target URL have random message ID generator code like this

https://<host>:<port>/sap/bc/srt/scs/sap/businesspartnererpreplicationi?MessageId=${=java.util.UUID.randomUUID()}


How can I add new users and authorizations in SAP HCI tenant? Who is authorised to add new users?
An admin user can go to HANA Cloud Platform cockpit and add further admin and users and assign them roles and authorizations. By default, SAP HCI uses SAP Cloud identity provider. Hence all the users must have valid S—userids or P-user ids that can be requested/generated from Service Market Place or SAP Community Network.

Where are all the roles & authorizations mentioned, that can be assigned to users?
Please look at https://cloudintegration.hana.ondemand.com/PI/help > Operating SAP HCI > User Management for SAP HCI > Managing Users and Roles Assignments > Defining Authorizations

While replicating account, messages are failing with following dump error?

Short dump: AP-BP-OR – MESSAGE_TYPE_X_TEXT – CL_COD_OUTBOUND_ERROR_HANDLINGCP

Check if the communication arrangement “Deprecated: Account Inbound for IDocs” is active, and the ERP integration for Cloud for Customer to ERP is scoped correctly.

During check connection with HCI iflow from S4Hana system, I get the following error
Inbound processing in endpoint /COD/ERP/SimpleConnect failed with message “Fault:HTTP verb was not GET or POST”

This is expected error with HCI however this also confirm your connectivity with HCI is working fine. Please refer the following note for more details.
https://launchpad.support.sap.com/#/notes/0002400906

While replicating account from C4C to ERP using HCI with certificate-based authentication, we are getting following error in C4C:
“SRT: HTTP error: (“HTTP Code 500: Internal Server Error – Details see in error log of transaction SRTUTIL”)’ also, HCI tail log shows following error: ‘Inbound processing in endpoint at https://abcdefg.xyz.hana.ondemand.com/cxf/COD/ERP/BusinessPartnerReplicationin failed with message “[CXF][Transport][HttpException]:HTTP response ‘401: Unauthorised’ when communicating with https://host.com:443/sap/bc/srt/idoc?sap-client=100“, caused by “HTTP response ‘401: Unauthorized’ when communicating with https://host.com:443/sap/bc/srt/idoc?sap-client=100

You could have following problems:

1) If host.com is a reverse proxy in front of on-premise then it might be that it is not forwarding the HCI client certificate in HTTP header to ERP(intermediate might be not trustworthy)
2) You did not map the HCI client cert in ERP SM30 vusrextid
3) The HCI client cert is not trusted on host.com

By retrieving the packaging information from BADI package_changes which is called in CL_AMDCI_OCNRQ_A_PEND_PACK_CH – Execute results into et_package of 2.6 million records and causes a dump.

“Short dump: AP-RC-MCI – TSV_TABH_POOL_NO_ROLL_MEMORY -CL_AMDCI_OCN_REQUEST==========CP”

You have loaded a huge amount of business partner addresses (IDOC ADRMAS) and contact person workplace addresses (IDOC ADR3MAS) without loading the mandatory business partners via IDOC DEBMAS_CFS. All the transferred messages are failing in the Cloud for Customer inbound, because they have a missing reference, due to the fact, that the corresponding DEBMAS_CFS was not processed.
Check whether you can send the corresponding DEBMAS_CFS IDOCS and afterwards restart the failed messages in Cloud for Customer. If this is not possible, cancel the failed messages in Cloud for Customer.

While replicating employee replication I receive the following error.
Error: Start date must not be later than end date Interface error; WS-Application; LOD-HCM-RPL; HumanCapitalManagementMasterDataReplicationEmploye

Following messages failed due to start-date greater then end-date. There are number of places where <ValidityPeriod> node appear in the payload and has <StartDate> and <EndDate> elements.Value of <StartDate> should be less than value of <EndDate>. But if messages have <StartDate> greater than <EndDate>. Then it will fail with above error. Please check the payload and re-trigger the messages.

While deploying integration flow, I receive the following error
“Erroneous Integration Flows is CRITICAL.”
Above error occurs when you deploy iflow with the same name again. Hence, check and remove any existing duplicate iflow from HCI tenant.

While updating an ERP Customer from C4C in ERP sales area fields gets deleted.
This happens whenever in the IDOC the E1KNVVM segment does not contain the value “/” for all the fields, which should not be touched during replication. In the most recent SP for the middleware content, the logic is available. Please update your content accordingly. If you prefer to fix the message mapping manually, please assign the constant value / to all of the fields in IDOC segment E1KNVVM, which are not already mapped. This should fix the issue.

While replicating data between PI to Cloud for Customer, it is failing with Certificate Error ( PI -> HTTPS -> C4C)
One of the reason could be that complete chain of SAP Hybris Cloud for Customer server certificate is not imported in PI trust store. Try importing complete chain and check if this resolves the error or not. In case if this doesn’t resolve error , please take SMICM trace at level 3 for more detailed info.

Dump occurs if you click on “Document Flow” in sales quote . Following are the steps to reproduce dump. :Woc Sales => Sales Quote “xyz” -> select “Document Flow” -> Exception Occurred.
An internal error occurred during message processing. For the error, details check MPL ID AFVbI-YbL8jty25IcWoKaRREfwjV in message monitoring.
Above error comes when processing stops at HCI for some reason. Please go through the complete log in HCI and search with given MPL ID for more detail info on error.

Why is employee address replication failing with following ID mapping error?
Error: “ID mapping for external value 148778 of Address missing”
Check SAP Note 2056045 – Initial Load of Business Partner from ERP to C4C should be done in a sequence.

When replicating data from ERP to Cloud for Customer via HCI, I receive the following error in ERP:
IOException:Unable to tunnel through proxy. Proxy returns
“HTTP/1.1 502 Host not found”
One of the reason could be that proxy settings are not maintained correctly in transaction sm59. Please check hostname,port, proxy again. In case if this doesn’t resolve the issue , further details could be obtained via SMICM trace at level 3.

While deploying iflow I am getting following error:
‘java.lang.IllegalStateException: Secure Storage service returns no credentials for alias XYZ’

This error occurs when iflow is deployed with basic authentication and credential name XYZ is not deployed into the tenant. It is mandatory to deploy credential in your HCI tenant with given name as maintained at receiver channel before using basic authentication in iflow .

During simulation or replication my scenario is failing with following error in PI:
XIAdapterFramework:GENERAL:com.sap.engine.interfaces.messaging.api.exception.MessagingException: com.sap.aii.af.service.administration.api.cpa.CPAChannelStoppedException: Channel stopped by administrative task.

Please check the status of receiver communication channel and sender communication channel in PI using URL https://<PI Host>:<Port>/mdt/channelmonitorservlet
If any of the channel is inactive then activate it.