Skip to Content

Hello, folks.

In this article I want to talk about the opportunity to catch and return to sender-system different types of exceptions which can be occurred in synchronous scenarios in SAP PI with help of custom EJB module at sender communication channel.

For better understanding, what for do we need that module, let’s take a look at one particular example: sender-system calling SAP PI SOAP service synchronously, then SAP PI calling receiver-system, let’s say some database(JDBC-receiver) and returning response to original sender-system. One of requirements from sender-system to this service could be following: it expects response message in one strict format no matter was database call successful or for some reason an exception was occurred during executing integration scenario. Could be that sender-system expects some certain elements to be filled with values in case of exception or error.

Example: sender-system sends SOAP request with CompanyID expecting to get some extra info about that company from receiver-system.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:test:company">
	<soapenv:Header/>
	<soapenv:Body>
		<urn:CompanyInfo_Request>
			<CompanyID>771575035533</CompanyID >
		</urn:CompanyInfo_Request>
	</soapenv:Body>
</soapenv:Envelope>

In case of successful call, response message from database going to look like this:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:test:company">
	<soapenv:Header/>
	<soapenv:Body>
		<urn:CompanyInfo_Response>
			<status>0</status>
			<error_text/>		 
			<DateExcerpt>2017-04-28</DateExcerpt>
			<OGRN>317774600137769</OGRN>
			<DateOGRN>2017-03-22</DateOGRN>
			<INN>771575035533</INN>
			<CodeTypeIP>1</CodeTypeIP>
			<NameTypeIP>1</NameTypeIP>
			<PhysicalPerson>
				<DateStart>2017-03-22</DateStart>
				<GRN>317774600137769</GRN>
				<PhysicalNameRus>
					<FirstName>Sergey</FirstName>
					<LastName>Alekseev</LastName>
					<MiddleName>Aleksandrovich</MiddleName>
				</PhysicalNameRus>
			</PhysicalPerson>
		</urn:CompanyInfo_Response>
	</soapenv:Body>
</soapenv:Envelope>

Note that response message has <status> and <error_text> elements: in case of successful DB call <status> filled with “0” in response message mapping and <error_text> is empty. But in case if some type of error taken place during the execution of this scenario, sender-system expects <status> to be filled with certain error-code and <error_text> filled with error description.

Now, imagine database server is unavailable or user which credentials used in receiver communication channel has been locked. What sender-system will receive in this case? Response message will look approximately like this (Note: In case of HTTP_AAE or REST sender adapters response message will look slightly different but not tremendously helpful):

<SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
	<SOAP:Body>
		<SOAP:Fault>
			<faultcode>SOAP:Server</faultcode>
			<faultstring>Server Error</faultstring>
			<detail>
				<s:SystemError xmlns:s="http://sap.com/xi/WebService/xi2.0">
					<context>XIAdapter</context>
					<code>ADAPTER.JAVA_EXCEPTION</code>
					<text>com.sap.engine.interfaces.messaging.api.exception.MessagingException: com.sap.engine.interfaces.messaging.api.exception.MessagingException: Error when attempting to get processing resources: com.sap.aii.af.lib.util.concurrent.ResourcePoolException: Unable to create new pooled resource: DriverManagerException: Cannot establish connection with the registered driver. com.microsoft.sqlserver.jdbc.SQLServerDriver returns: Login failed for user 'test1'..
: com.microsoft.sqlserver.jdbc.SQLServerException: Login failed for user 'test1'. 
at com.sap.aii.adapter.soap.web.SOAPHandler.processSOAPtoXMB(SOAPHandler.java:772)
at com.sap.aii.adapter.soap.web.MessageServlet.doPost(MessageServlet.java:530)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
at javax.servlet.http.HttpServlet.__AW_service(HttpServlet.java:847)
at javax.servlet.http.HttpServlet.service(HttpServlet.java)
. . .
					</text>
				</s:SystemError>
			</detail>
		</SOAP:Fault>
	</SOAP:Body>
</SOAP:Envelope>

As we can see, in case if any exception has been occurred while message being processed through integration engine pipeline, client system will receive response message with error stack trace in strictly defined structure. Response operation mapping being ignored and there is no standard way to change SAP-defined adapter exception message structure.

In order to overcome this problem I have developed custom EJB module, which can be used on sender communication channel supporting synchronous communication (SOAP, REST, HTTP adapters). In case of successful processing message through integration engine pipeline, client system will receive response message from receiver-system – standard processing of response message from receiver-system won’t be affected by this custom module. But in case if some exception occurred at any stage of integration engine pipeline execution (receiver determination, operation mapping, receiver system call etc.), custom module will catch that exception and call certain operation mapping, which name we’ll submit as a parameter of this module. Original message will be processed to this operation mapping (BI or AM version depending on a module parameter value) and exception description if needed. Result of execution this operation mapping will return to a sender system, so we can define structure of this response message for those cases when exception during pipeline message processing occurred.

EAR project which is ready for deploy can be downloaded from github repository by following link:

https://github.com/IAlekseev91/customModulePI

To use this module you will have to remove standard module entry in Processing Sequence on the “Module” tab in sender communication channel. Exactly replace standard module entry (in many cases – CallSapAdapter) with localejbs/CustomAdapterBean. In case if you want or need to use standard for default module parameters, you may as well use them with CustomAdapterBean.



Also I do recommend you to use key “cab” for this custom module because it will generate entries in message audit log and communication channel monitor processing log starting with this prefix.

Table with parameters available for use with CustomAdapterBean module:

Parameter name Available values Default value Obligatory parameter Description
catchException true/false false no True – when exception/error being occurred, its being caught by module and processed considering parameters listed below.
False – module works just as a standard module which has been removed from processing sequence.
Being used for switching to standard message processing on the go.
moduleName string value localejbs/CallSapAdapter no Name of standard module that has been removed from processing sequence.
operationSpecific true/false false no True – in case of multiple operations on sender service interface for every operation distinct operation mapping will be executed in case of exception/error.
operationMappingName string value yes, when operationSpecific = false Operation mapping name which going to be executed upon exception/error while processing message.
Has to be unique across the whole ESR.
operationName.*
where * – serial number of service interface operation
string value yes, when operationSpecific = true Name of service interface operation.
operationMappingName.*
where * is a serial number of service interface operation, which particular operation mapping will be called for
string value yes, when operationSpecific = true Operation mapping name which is going to be executed for particular service interface operation in case of exception/error while processing message.
When set up as “null” no operation mapping for particular service interface operation will be executed. Sender-system will receive error message in default adapter format.
Has to be unique across the whole ESR.
saveOriginalMessage true/false false no True – original request from sender system (BI version) will be transferred to error handling operation mapping from module’s parameter.
Vice versa, when set as “false”, AM version of original request will be transferred to error handling operation mapping from module’s parameter.
Keep in mind “false” value requires additional attention to message structures when creating ErrorHandling operation mapping.
For example, if exception/error will take place before AM version of original request has been created in pipeline, module will try to execute ErrorHandling operation mapping for BI version of original request.
saveException true/false false no True – error description being saved in attachment with opportunity of its following extraction in operation mapping.
wsUser string value yes Name of SAP PI user account. User has to be able to call web services (SAP_XI_APPL_SERV_USER role)
pwd.wsPassword string value yes User account password.
saveLogVersion true/false false no True – after execution of operation mapping which has been set up in parameter message version being saved in Message Editor: Versions, displayed with caption “Fault”.

If SAP PI/PO landscape you work with includes SAP Web Dispatcher, you will need to submit the address of SAP WD to this custom module parameter. To accomplish that you will need to edit application settings: host:port/nwa -> Configuration -> Infrastructure -> Application Modules. On the overview tab you filter applications by name “moduleCustomAdapterEJB.jar” and then input the web address of SAP Web Dispatcher as value for parameter “addressSAPWD” at the “Environment and References” tab.



Let’s make an example considering all mentioned above using CustomAdapterBean.

Parameters for module will look like this:

Parameter name Parameter value
catchException true
operationMappingName om_getCompany_errorHandling
saveException true
saveOriginalMessage true
wsUser pi_user
pwd.wsPassword *****

Beforehand, in Enterprise Service Builder operation mapping om_getCompany_ErrorHandling has been created. It will be called by custom module upon catching exception while processing message through integration engine pipeline. Source operation is going to be sender service interface original operation, for target operation you going to have to create service interface intentionally (let’s call it *_errorHandling) and set up as a request structure the one you wish sender system to receive in case of exception during message processing through pipeline (in many cases it’s going to be same as original sender service interface operation response structure).

As far as sender service interface operation is synchronous, target operation also has to be synchronous. Meanwhile response structure does not have any meaning and won’t be used ever – operation mapping will ignore it.

It is only important to set mapping programm for request which is going to create target response structure for original sender service interface operation and will be received by sender-system. For the sake of our example we can use next type of message mapping:



Element <status> we will fill with digit value signalizing about exception during message processing.



Element <error_text> we’ll fill with error description text concatenated with value of element <CompanyID> from original request message.

Error description text can be extracted with help of user defined function “getAttachmentById”. As mentioned above, error text will be saved in attachment (by setting value of custom module parameter “saveException” to “true”), so for it’s extraction UDF will be needed. Check code of this UDF below:


public String getAttachmentById(String id, Container container) throws StreamTransformationException {
	InputAttachments inputAttach = container.getGlobalContainer().getInputAttachments();
	if (inputAttach.areAttachmentsAvailable()) {
		Attachment attach = inputAttach.getAttachment(id);
		if (attach == null) {
			throw new StreamTransformationException("Unable to find attachment with id: " + id);
		}
		return new String(attach.getContent());
	} else {
		throw new StreamTransformationException("Attachments not available. Please check that the parameter 'Read attachment' in operation mapping is set to true");
	}
}

Custom module will save attachment under name “Exception” so this name has to be used as an input parameter for UDF.

Let’s see what sender-system will receive in case of error.

Request message from sender-system:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:test:company">
	<soapenv:Header/>
	<soapenv:Body>
		<urn:CompanyInfo_Request>
			<CompanyID>771575035533</CompanyID >
		</urn:CompanyInfo_Request>
	</soapenv:Body>
</soapenv:Envelope>

Response:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:test:company">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:CompanyInfo_Response>
		 <status>1</status>
		 <error_text>Error while get info for Company with id 771575035533:  com.sap.engine.interfaces.messaging.api.exception.MessagingException: com.sap.engine.interfaces.messaging.api.exception.MessagingException: Error when attempting to get processing resources: com.sap.aii.af.lib.util.concurrent.ResourcePoolException: Unable to create new pooled resource: DriverManagerException: Cannot establish connection with the registered driver. com.microsoft.sqlserver.jdbc.SQLServerDriver returns: Login failed for user 'test1'..: com.microsoft.sqlserver.jdbc.SQLServerException: Login failed for user 'test1'</error_text>		 
      </urn:CompanyInfo_Response>
   </soapenv:Body>
</soapenv:Envelope>

As we can see, in case if there was an error occurred while trying to establish connection to database (receiver-system), we have received response in desired structure.

I’ll be glad if this module will help you out with structuring responses according to format defined by sender-system.

Thanks for reading and good luck.

Thanks for help to Ivan Mamontov.

To report this post you need to login first.

3 Comments

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

Leave a Reply