Skip to Content

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.

NWDS.png

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.

/wp-content/uploads/2014/10/local_class_552985.png

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.

/wp-content/uploads/2014/10/name_553028.png

Input file

Location of input file in the local machine running NWDS should be changed accordingly.

/wp-content/uploads/2014/10/input_553029.png

Dynamic configuration

Optionally, dynamic configuration can be simulated by adding the entries in the test class using static method addDynCfg(namespace, attribute, value).

/wp-content/uploads/2014/10/dyncfg_553034.png

Module parameters

Optionally, module parameters can be entered to simulate entries in the module chain by using method put(parameterName, parameterValue).

/wp-content/uploads/2014/10/module_parameters_553036.png

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.

/wp-content/uploads/2014/10/output_553038.png

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
/wp-content/uploads/2014/10/input_553029.png /wp-content/uploads/2014/10/output_553038.png

Dynamic configuration values displayed in Console output

/wp-content/uploads/2014/10/console1_553744.png

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

NWDS Download Links – Java Development – SCN Wiki

To report this post you need to login first.

12 Comments

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

  1. HariKumar Vemuri

    Hi Eng Swee,

    Thanks for great blog !

    I tried to implement same program in my environment. My program has no errors, but while running the class i got below exception. Could you please let me know how to sort it out ?

    java.lang.NoClassDefFoundError: com/sap/engine/interfaces/messaging/api/XMLPayload

    Caused by: java.lang.ClassNotFoundException: com.sap.engine.interfaces.messaging.api.XMLPayload

      at java.net.URLClassLoader$1.run(URLClassLoader.java:202)

      at java.security.AccessController.doPrivileged(Native Method)

      at java.net.URLClassLoader.findClass(URLClassLoader.java:190)

      at java.lang.ClassLoader.loadClass(ClassLoader.java:306)

      at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)

      at java.lang.ClassLoader.loadClass(ClassLoader.java:247)

    Exception in thread “main”

    Thank You !

    Regards

    HariKumar.

    (0) 
    1. Eng Swee Yeoh Post author

      Hi HariKumar

      What environment are you using – which NWDS version?

      As mentioned in the “Additional Reference” section of the blog, you will need to include the necessary PI adapter JAR files.

      If you are on NWDS 7.3x, it you already come with the JAR files, so you just need to include the libraries – see screenshot below:-

      /wp-content/uploads/2016/01/lib_860686.png

      Rgds

      Eng Swee

      (0) 
      1. HariKumar Vemuri

        Hello Eng Swee,

        Thanks for response, Looks like NWDS (7.3 SP 14) in my personal laptop is corrupted. But same code executed successfully in my workstation 🙂 . Thanks for nice blog, you saved a lot of time for Adapter module testing.

        Regards

        HariKumar.

        (0) 

Leave a Reply