Update 2 Oct 2014: Added section regarding usage of Audit Log
Background
While custom adapter module development is becoming more common, there is still no functionality built into the NWDS/Eclipse IDE to perform basic testing of the module logic. As described by threads like this, it is a pain to redeploy the module into the server each time there are code changes. The adapter module can only be tested in an end-to-end scenario. Even for Proof-Of-Concept developments, a full integration scenario needs to be configured in order to test the module.
This blog attempts to help to reduce the pain in adapter module development by providing an approach to easily perform basic/unit testing prior to server deployment.
This is achieved by introducing a testing class with a static Main method as a wrap-around of the module class. This testing class can then be executed in the IDE directly.
Limitations
Please be aware that there are limitations to this approach as it is meant for basic/unit testing only. Certain scenario examples in the non exhaustive list below still require end-to-end testing.
- scenarios with dependencies on output of prior module in the module chain
- scenarios with dependencies on actual payload generated by sender adapter
- scenarios that requires connectivity to certain resources (HTTP, FTP, etc) that are not available from the local PC
- scenarios with attachments
Source code
The full source code can be found in the following public repository on GitHub.
GitHub repository for equalize-xpi-tester
Details and Usage
Below are the details of this approach and also an explanation on the different sections, and how those could be changed so that standalone testing can be performed in NWDS.
Testing class with Main method
Create a new testing class with a main method. Ideally put this in a separate package, so that this can be excluded when generating the files for deployment. Copy the source code provided above into the new class - take note of any package renaming as necessary.
Local implementation classes
Several interfaces do not have corresponding implementation classes in the PI JAR library files. In order to be able to compile the test class, the following classes shown below are local classes implementing those interfaces. These only provide basic implementation for testing and are not the same as the full implementation classes in the Adapter Engine.
Module class and message details
Below shows the portion of the code where the module bean is instantiated. This should be changed according to the name of the module bean being developed.
The message details (sender/receiver details, protocol, etc) can also be changed accordingly.
Input file
Location of input file in the local machine running NWDS should be changed accordingly.
Dynamic configuration
Optionally, dynamic configuration can be simulated by adding the entries in the test class using static method addDynCfg(namespace, attribute, value).
Module parameters
Optionally, module parameters can be entered to simulate entries in the module chain by using method put(parameterName, parameterValue).
Module processing and output file
Actual processing logic of the module is executed by the call to the process method of the bean.
Location of output file in the local machine running NWDS should be changed accordingly.
Example Module
Below is a simple example of a custom module (the full code is found in the GitHub repository above) to demonstrate unit testing in NWDS.
The module changes the name of the root element and also adds a prefix to the dynamic configuration filename if module parameter PARAM1 is configured.
Logic
public ModuleData process(ModuleContext moduleContext, ModuleData inputModuleData) throws ModuleException {
try {
// Get input stream
Message msg = (Message) inputModuleData.getPrincipalData();
XMLPayload payload = msg.getDocument();
InputStream inStr = payload.getInputStream();
// Get the text content
BufferedReader br = new BufferedReader(new InputStreamReader(inStr));
ArrayList<String> contents = new ArrayList<String>();
String lineContent;
while ((lineContent = br.readLine()) != null) {
contents.add(lineContent);
}
br.close();
// Modify the root element name
StringBuilder sb = new StringBuilder();
for( String line: contents ) {
if ( line.contains("MT_Calculator_Input")) {
line = line.replace("MT_Calculator_Input", "New_Root");
sb.append(line);
} else {
sb.append(line);
}
sb.append("\n");
}
// Set changed content
payload.setContent(sb.toString().getBytes());
// If PARAM1 is configured in the module parameters, add that as a prefix to the file name
String param1 = moduleContext.getContextData("PARAM1");
if (param1 != null) {
// Get Dynamic Configuration
MessagePropertyKey fileNameKey = new MessagePropertyKey("FileName", "http://sap.com/xi/XI/System/File");
String fileName = msg.getMessageProperty(fileNameKey);
// Set new value Dynamic Configuration
msg.removeMessageProperty(fileNameKey);
msg.setMessageProperty(fileNameKey, param1 + "_" + fileName );
}
// Update the message
inputModuleData.setPrincipalData(msg);
} catch (Exception e) {
throw new ModuleException(e.getClass() + ": " + e.getMessage());
}
return inputModuleData;
}
Input and results
Input File | Output File |
---|---|
Dynamic configuration values displayed in Console output
Audit Log Usage
Audit log is an important logging functionality to provide accurate status of the processing of module. However, audit log is not available during standalone testing in NWDS. Execution of method getPublicAPIAccess of PublicAPIAccessFactory will raise a MessagingException. In order to workaround this, the exception can be caught in a try-catch block, and adding to the audit log is only performed if the audit log object is instantiated. Optionally, for testing in NWDS, the message can be sent to the console output.
Below is the snippet of the logic to handle audit log instantiation and message entry.
// Get audit log
MessageKey key = new MessageKey(msg.getMessageId(), msg.getMessageDirection());
try {
audit = PublicAPIAccessFactory.getPublicAPIAccess().getAuditAccess();
} catch (MessagingException e) {
System.out.println("WARNING: Audit log not available in standalone testing");
}
addLog(key, AuditLogStatus.SUCCESS, "CustomFunctionBean: Module Called");
Logic for private method addLog.
private void addLog (MessageKey msgKey, AuditLogStatus status, String message) {
if (audit != null) {
audit.addAuditLogEntry(msgKey, status, message);
} else {
System.out.println( "Audit Log: " + message);
}
}
Additional Reference
Official step-by-step guides by SAP on how to create custom modules
How to Create Modules for the J2EE Adapter Engine (NW2004)
How to Create Modules for the J2EE Adapter Engine (NW7.0)
How to Create Modules for the JEE Adapter Engine 7.1
Developing User Enhancement Modules in the Adapter Engine
Location of JAR library files for Module development
Where to get the libraries for XI development - Process Integration - SCN Wiki
For NWDS 7.3, JAR files are automatically provided by NWDS, so just need to include the XPI Library as shown in the thread below
Issue in Excel to XML Conversion
Links for downloading different versions of NWDS
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
9 | |
8 | |
6 | |
5 | |
4 | |
4 | |
4 | |
3 | |
3 | |
3 |