Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
former_member182412
Active Contributor

Introduction


Sometimes there is a requirement to send the synchronous response immediately without waiting to process the message in receiver side like this question SOAP to IDOC scenario in PI 7.31 ICO (send message id back to SOAP Client), previously we used ccBPM to achieve this requirement, with in the BPM open sync/async bridge and generate the response using mapping step and send it to sender then send the message asynchronously to the receiver.

This requirement is not possible to send the immediate sync response message to the sender even with sync/async bridge using adapter modules without BPM.

In this blog i want to show how we can achieve this using custom adapter module.

Design


Create below sender data type for web service request.


Create below sender data type for web service response.


Create below data type for receiver file.


Create sender service interface for web service synchronous request.


Create below service interface for receiver file.


Create below simple message mapping from sender web service request to receiver file structure.


Configuration

Create below IFlow for synchronous web service request to File. (SOAP to File).



Configure below custom adapter module in SOAP sender channel.


Configure file receiver channel normally.


The below is the custom adapter module SyncAsyncResponseBean module which is configured in SOAP sender channel. This adapter module change the synchronous request to asynchronous and send the message to messaging system asynchronously. After that generate the response message using below CreateWebserviceResponse class and send the response message to sender.
import java.rmi.RemoteException;

import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.transaction.Transaction;

import com.sap.aii.adapter.xi.ms.XIMessage;
import com.sap.aii.af.app.modules.orch.MessagingBeanBase;
import com.sap.aii.af.lib.mp.module.ModuleContext;
import com.sap.aii.af.lib.mp.module.ModuleData;
import com.sap.aii.af.lib.mp.module.ModuleException;
import com.sap.aii.af.service.cpa.CPAObjectType;
import com.sap.aii.af.service.cpa.Channel;
import com.sap.aii.af.service.cpa.LookupManager;
import com.sap.engine.interfaces.messaging.api.DeliverySemantics;
import com.sap.engine.interfaces.messaging.api.Message;
import com.sap.engine.interfaces.messaging.api.MessageClass;
import com.sap.engine.interfaces.messaging.api.XMLPayload;

public class SyncAsyncResponseBean extends MessagingBeanBase implements SessionBean {
private static final long serialVersionUID = -5736277688013260902L;

public ModuleData process(ModuleContext moduleContext, ModuleData moduleData) throws ModuleException {
init();
try {
Channel channel = LookupManager.getInstance().getCPAObject(CPAObjectType.CHANNEL, moduleContext.getChannelID());
Message reqMsg = (Message) moduleData.getPrincipalData();
reqMsg.setDeliverySemantics(DeliverySemantics.ExactlyOnce);
if ((this.txmanager != null) && (this.txmanager.getStatus() == 6)) {
Transaction tx = (Transaction) moduleData.getSupplementalData("transaction");
if (tx != null) {
this.txmanager.resume(tx);
}
}
retrieveConnection(moduleContext, channel).send(reqMsg);
Message respMsg = this.afMessageFactory.createMessage(reqMsg.getToParty(), reqMsg.getFromParty(), reqMsg
.getToService(), reqMsg.getFromService(), reqMsg.getAction());
XMLPayload respPayload = respMsg.createXMLPayload();
respPayload.setContent(new CreateWebserviceResponse().transform(reqMsg));
respMsg.setDocument(respPayload);
((XIMessage) respMsg).setMessageClass(MessageClass.APPLICATION_RESPONSE);
respMsg.setDeliverySemantics(DeliverySemantics.BestEffort);
respMsg.setRefToMessageId(reqMsg.getMessageId());
moduleData.setPrincipalData(respMsg);
return moduleData;
} catch (Exception e) {
throw new ModuleException(e.getMessage(), e);
}
}

public void ejbActivate() throws EJBException, RemoteException {
}

public void ejbPassivate() throws EJBException, RemoteException {
}

public void ejbRemove() throws EJBException, RemoteException {
}

public void setSessionContext(SessionContext arg0) throws EJBException, RemoteException {
}
}

Code for CreateWebserviceResponse is below.
import java.io.ByteArrayOutputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.sap.aii.af.lib.mp.module.ModuleException;
import com.sap.engine.interfaces.messaging.api.Message;

public class CreateWebserviceResponse {

public byte[] transform(Message msg) throws ModuleException {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
factory.setIgnoringElementContentWhitespace(true);
Document outputDoc = builder.newDocument();
Element outMsgType = outputDoc.createElement("ns0:WebserviceResponse");
outMsgType.setAttribute("xmlns:ns0", "http://mycompany.org");
outputDoc.appendChild(outMsgType);
Element messageIdElement = outputDoc.createElement("MessageId");
messageIdElement.setTextContent(msg.getMessageId());
outMsgType.appendChild(messageIdElement);
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
transformer.setOutputProperty("indent", "yes");
DOMSource source = new DOMSource(outputDoc);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
StreamResult result = new StreamResult(baos);
transformer.transform(source, result);
return baos.toByteArray();
} catch (Exception e) {
throw new ModuleException(e.getMessage(), e);
}
}
}

Include these two references in the application-j2ee-engine.xml which you created in the EAR application, the module is used classes from these applications.
<reference 
reference-type="hard">
<reference-target
provider-name="sap.com"
target-type="service">com.sap.aii.adapter.xi.svc</reference-target>
</reference>
<reference
reference-type="hard">
<reference-target
provider-name="sap.com"
target-type="application">com.sap.aii.af.app</reference-target>
</reference>

Testing


Send the web service request from SOAP UI and you can see below we got the response with message id which created in PI to the sender web service.


You can see below audit log which shows the message successfully sent to messaging system asynchronously and then send the response back to the sender.



The file successfully placed in the target folder.


We can see the file content what we expected after the mapping.

Conclusion


Using above custom adapter module we can send the synchronous response message  immediately without waiting for message processing in receiver side.  I hope this help to the community.
6 Comments
Labels in this area