Adapter Module: AdapterModuleDCBypass
ody>
Adapter Module: AdapterModuleDCBypass
Use
Some adapters support specific message attributes, which contain additional information about messages. This information is not located in the payload of the message, but in additional message header fields called Dynamic Configuration. These attributes can be accessed in routing and mapping by using the attribute namespace and the technical name of the attribute.
Every time an adapter module is executed, message header is transferred from input to output message. However, when using Integrated Configuration Objects (ICOs), this header section is omitted on synchronous scenarios. The result is Dynamic Configuration section’s missing.
You use AdapterModuleDCBypass module to prevent Dynamic Configuration attributes to be deleted after adapter module is executed. It uses Supplemental Data, a Module Data area, to store temporarily all Dynamic Configuration properties before adapter module execution. Afterwards, AdapterModuleDCBypass retrieve all the properties stored in Supplemental Data and writes them back to Dynamic Configuration section.
Deployment
Enterprise Java Bean Project: AdapterModuleDCBypass-ejb
Enterprise Java Bean Application: AdapterModuleDCBypass-ear
Integration
The module can be used in any Sender or Receiver Adapter.
Activities
This section describes all the activities that have to be carried out in order to configure the module.
Entries in processing sequence
Insert the module before and after the adapter module as shown in the picture below.
Entries in the module configuration
The table below shows the possible parameters and values of the adapter module.
Parameter | Type | Possible Values | Description |
---|---|---|---|
mode | required | DynamicConfiguration_to_ModuleData | ModuleData_to_DynamicConfiguration |
The mode parameter specifies the execution mode of the module. When mode is [DynamicConfiguration_to_ModuleData] the module retrieves attributes from Dynamic Configuration and copies them to Module Data. When mode is [ModuleData_to_DynamicConfiguration] the module retrieves attributes from Module Data and copies them to Dynamic Configuration. |
Audit Log
The execution process can be followed in the audit log generated per message.
AdapterModuleDCBypassBean
package com.rav.integrations.modules;
import java.rmi.RemoteException;
import java.util.Enumeration;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.ejb.TimedObject;
import javax.ejb.Timer;
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.auditlog.Audit;
import com.sap.engine.interfaces.messaging.api.Message;
import com.sap.engine.interfaces.messaging.api.MessageKey;
import com.sap.engine.interfaces.messaging.api.MessagePropertyKey;
import com.sap.engine.interfaces.messaging.api.auditlog.AuditLogStatus;
import java.sql.Timestamp;
/**
* @author rallue
*
*/
public class AdapterModuleDCBypassBean implements SessionBean, TimedObject {
private static final long serialVersionUID = -1910739162843853923L;
private static final String C_MODE_DC2MD = "DynamicConfiguration_to_ModuleData";
private static final String C_MODE_MD2DC = "ModuleData_to_DynamicConfiguration";
private static final String C_PARAM_MODE = "mode";
private static final String C_KEY_SEPARATOR = "#";
private static MessageKey amk;
/*
* (non-Javadoc)
*
* @see javax.ejb.SessionBean#ejbActivate()
*/
@Override
public void ejbActivate() throws EJBException, RemoteException {
// TODO Auto-generated method stub
}
/*
* (non-Javadoc)
*
* @see javax.ejb.SessionBean#ejbPassivate()
*/
@Override
public void ejbPassivate() throws EJBException, RemoteException {
// TODO Auto-generated method stub
}
/*
* (non-Javadoc)
*
* @see javax.ejb.SessionBean#ejbRemove()
*/
@Override
public void ejbRemove() throws EJBException, RemoteException {
// TODO Auto-generated method stub
}
/*
* (non-Javadoc)
*
* @see javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext)
*/
@Override
public void setSessionContext(SessionContext arg0) throws EJBException,
RemoteException {
// TODO Auto-generated method stub
}
/*
* (non-Javadoc)
*
* @see javax.ejb.TimedObject#ejbTimeout(javax.ejb.Timer)
*/
@Override
public void ejbTimeout(Timer arg0) {
// TODO Auto-generated method stub
}
public void ejbCreate() throws javax.ejb.CreateException {
}
public ModuleData process(ModuleContext moduleContext,
ModuleData inputModuleData) throws ModuleException {
String mode = "";
Message msg;
try {
msg = (Message) inputModuleData.getPrincipalData();
amk = new MessageKey(msg.getMessageId(), msg.getMessageDirection());
addInfo("AdapterModuleDCBypassBean begin...");
try {
mode = moduleContext.getContextData(C_PARAM_MODE);
if (mode != null && !mode.equals(C_MODE_DC2MD)
&& !mode.equals(C_MODE_MD2DC)) {
mode = C_MODE_DC2MD;
}
} catch (Exception e) {
mode = C_MODE_DC2MD;
}
if (mode.equals(C_MODE_DC2MD)) {
addInfo("AdapterModuleDCBypassBean: mode - " + C_MODE_DC2MD);
dcToMD(inputModuleData);
} else if (mode.equals(C_MODE_MD2DC)) {
addInfo("AdapterModuleDCBypassBean: mode - " + C_MODE_MD2DC);
mdToDC(inputModuleData);
}
} catch (Exception e) {
addInfo("AdapterModuleDCBypassBean: Exception found: "
+ e.getMessage());
}
addInfo("AdapterModuleDCBypassBean end...");
return inputModuleData;
}
@SuppressWarnings("unchecked")
private void mdToDC(ModuleData inputModuleData) throws ModuleException {
Message msg = null;
MessagePropertyKey key;
String propertyName = "";
String propertyNamespace = "";
String supplementalDataName;
String supplementalData;
String[] str;
try {
msg = (Message) inputModuleData.getPrincipalData();
Enumeration<String> supplementalDataNamesList = inputModuleData
.getSupplementalDataNames();
while (supplementalDataNamesList.hasMoreElements()) {
try {
supplementalDataName = supplementalDataNamesList.nextElement();
if (supplementalDataName != null && supplementalDataName.contains(C_KEY_SEPARATOR)) {
supplementalData = (String) inputModuleData.getSupplementalData(supplementalDataName);
str = supplementalDataName.split(C_KEY_SEPARATOR);
if (str.length > 1) {
propertyName = str[0];
propertyNamespace = str[1];
key = new MessagePropertyKey(propertyName, propertyNamespace);
msg.setMessageProperty(key, supplementalData);
addInfo("mdToDC - propertyName = " + propertyName
+ " propertyNamespace = "
+ propertyNamespace
+ " supplementalData = " + supplementalData);
}
} else {
if (supplementalDataName == null) {
addInfo("mdToDC - Key ignored: supplementalDataName is null");
} else {
addInfo("mdToDC - Key ignored: supplementalDataName does not contain separator "
+ C_KEY_SEPARATOR
+ " : "
+ supplementalDataName);
}
}
} catch (Exception e) {
addInfo("mdToDC - Key ignored: something went wrong while trying to read a key : "
+ e.getMessage());
}
}
inputModuleData.setPrincipalData(msg);
} catch (Exception e) {
addInfo("mdToDC - Exception Found: " + e.getMessage());
throw new ModuleException(e.getMessage(), e);
}
}
private void dcToMD(ModuleData inputModuleData) throws ModuleException {
Message msg = null;
String propertyName = "";
String propertyNamespace = "";
String supplementalDataName;
String supplementalData;
try {
msg = (Message) inputModuleData.getPrincipalData();
for (MessagePropertyKey key : msg.getMessagePropertyKeys()) {
propertyName = key.getPropertyName();
propertyNamespace = key.getPropertyNamespace();
supplementalDataName = propertyName + C_KEY_SEPARATOR
+ propertyNamespace;
supplementalData = msg.getMessageProperty(key);
inputModuleData.setSupplementalData(supplementalDataName,
supplementalData);
addInfo("dcToMD - supplementalDataName = "
+ supplementalDataName + " supplementalData = "
+ supplementalData);
}
} catch (Exception e) {
addInfo("dcToMD - Exception Found: " + e.getMessage());
throw new ModuleException(e.getMessage(), e);
}
}
private void addInfo(String msg) {
try {
msg = System.nanoTime() + " : " + msg;
Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, msg);
} catch (Exception e) {
Audit.addAuditLogEntry(amk, AuditLogStatus.ERROR,
"Error opening the file!");
}
}
private void addWarning(String msg) {
try {
Audit.addAuditLogEntry(amk, AuditLogStatus.WARNING, msg);
} catch (Exception e) {
Audit.addAuditLogEntry(amk, AuditLogStatus.ERROR,
"Error opening the file!");
}
}
private void addError(String msg) {
try {
Audit.addAuditLogEntry(amk, AuditLogStatus.ERROR, msg);
} catch (Exception e) {
Audit.addAuditLogEntry(amk, AuditLogStatus.ERROR,
"Error opening the file!");
}
}
}
Great job Roger!
Super and nice alternate solution. Great work !! Roger
BTW, I am not sure if this a defect in all SAP PI/PO versions ICO's with synchronous mode not carrying dynamic configuration. If it is a defect in all current PI/PO versions, then SAP should fix this
Best Regards,
Praveen Gujjeti
Well I found it in a PI 7.31 system. I can't remember the SP level, but I hope SAP fixes it if it's a defect. While we wait for the final solution, it can be used as a workaround.
Best Regards,
Roger Allué Vall
For 7.40 SP11 this issue still persists.
Thank you very much for sharing. nice blog..
Awesome blog. Very Useful...
This workaround does not work with HTTP_AAE (as of PO 7.50 SP03): The Supplemental Data gets deleted by the Adapter Module sap.com/com.sap.aii.adapter.http/HttpAdapterBean, too.