Adapter Module: ReplaceString


Use

ReplaceString module is used to replace strings within the xml text of the payload of the message. It can be used to modify the message structure before it gets in PI and also before it gets out. It is useful when there are strings like namespaces, types, etc that PI can’t “understand” or that PI is unable to include in outbound messages.

The module obtains a pair of string : <OldString>;<NewString> as parameter. Reads the payload of the message and converts it to a string. Then it searches <OldString> within the message and replace each occurrence with <NewString>. Finally it returns the message modified. If OldString can’t be found in the message nothing is modified and the original message is returned.

The module accepts multiple string pairs to allow multiple replacements in a single execution.

Deployment

Enterprise Java Bean Project: ReplaceString-ejb

Enterprise Java Bean Application: ReplaceString-ear

Integration

The module can be used in any kind of Sender and Receiver adapters.

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 in front of 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 Example
separator Optional

Any alphanumeric character.

Default value: ‘|’

This parameter configures the character that separates a pair of strings.

separator = ‘;’
param(*)

Mandatory

Pair of strings separated by “separator” character.

<OldString><separator>[<NewString>, blankString,emptyString].

Default value: none.

This parameter is used to obtain Old string to be replaced by the New string in the message. The pair is separated by “separator”. As Adapter module tab in PI trims strings by the right side, if it’s needed to replace OldString by a blank string or an empty string, the parameters blankString or emptyString have to be used.

param1=str1;str2

param2=str1;blankString

param3=str1;emptyString

(*) The parameter name can be any string: param1, parameter, aaa, etc.

Example

Payload data before execution:


<MT_ROOT>
     <RECORDSET>
          <DATA>
               <FIELD1>value</FIELD1>
               <FIELD2>value</FIELD2>
               <FIELD3>value</FIELD3>
          </DATA>
          <DATA>
               <FIELD1>value</FIELD1>
               <FIELD2>value</FIELD2>
               <FIELD3>value</FIELD3>
          </DATA>
     </RECORDSET>
</MT_ROOT>





Module parameters:

separator = ‘;’

param1 = ’RECORDSET;ROW’

param2 = <MT_ROOT>;<MESSAGE type=TYPE>

param3 = </MT_ROOT>;</MESSAGE>

param4 = <DATA>;emptyString

param5 = </DATA>;emptyString

Payload data after execution:


< MESSAGE type=TYPE>
     <ROW>
          <FIELD1>value</FIELD1>
          <FIELD2>value</FIELD2>
          <FIELD3>value</FIELD3>
          <FIELD1>value</FIELD1>
          <FIELD2>value</FIELD2>
          <FIELD3>value</FIELD3>
     </ROW>
</MESSAGE>







ReplaceStringBean


/**
*
*/
package com.arms.integrations;
import java.rmi.RemoteException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import com.sap.aii.af.lib.mp.module.Module;
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.engine.interfaces.messaging.api.Message;
import com.sap.aii.af.service.auditlog.Audit;
import com.sap.engine.interfaces.messaging.api.MessageKey;
import com.sap.engine.interfaces.messaging.api.auditlog.AuditLogStatus;
import java.io.*;
import java.util.*;
/**
* @author Roger Allué i Vall
*
*/
public class ReplaceStringBean implements SessionBean, Module {
    private SessionContext myContext;
    private static final String C_SEPARATOR_STRING = "separator";
    private static final String C_AUX_SEPARATOR = "|";
    private static final String C_MODULEKEY_STRING = "module.key";
    private static final String C_BLANK_STRING = "blankString";
    private static final String C_EMPTY_STRING = "emptyString";
    /* (non-Javadoc)
     * @see javax.ejb.SessionBean#ejbActivate()
     */
    public void ejbActivate() throws EJBException, RemoteException {
        // TODO Auto-generated method stub
    }
    /* (non-Javadoc)
     * @see javax.ejb.SessionBean#ejbPassivate()
     */
    public void ejbPassivate() throws EJBException, RemoteException {
        // TODO Auto-generated method stub
    }
    /* (non-Javadoc)
     * @see javax.ejb.SessionBean#ejbRemove()
     */
    public void ejbRemove() throws EJBException, RemoteException {
        // TODO Auto-generated method stub
    }
    /* (non-Javadoc)
     * @see javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext)
     */
    public void setSessionContext(SessionContext arg0) throws EJBException,
            RemoteException {
        // TODO Auto-generated method stub
        myContext = arg0;
    }
    /* (non-Javadoc)
     * @see javax.ejb.SessionSynchronization#afterBegin()
     */
    public void afterBegin() throws EJBException, RemoteException {
        // TODO Auto-generated method stub
    }
    /* (non-Javadoc)
     * @see javax.ejb.SessionSynchronization#afterCompletion(boolean)
     */
    public void afterCompletion(boolean arg0) throws EJBException,
            RemoteException {
        // TODO Auto-generated method stub
    }
    /* (non-Javadoc)
     * @see javax.ejb.SessionSynchronization#beforeCompletion()
     */
    public void beforeCompletion() throws EJBException, RemoteException {
        // TODO Auto-generated method stub
    }
    public void ejbCreate() throws javax.ejb.CreateException {
    }
    public ModuleData process(ModuleContext moduleContext, ModuleData inputModuleData)    throws ModuleException {
        ByteArrayOutputStream payloadOut = null;
        int inputByte = 0;
        String payloadStr = "";
        Message msg;
        Enumeration paramList;
        String sep, paramKey,param, strArray[];
        try {
             msg = (Message) inputModuleData.getPrincipalData();
             MessageKey amk = new MessageKey(msg.getMessageId(), msg.getMessageDirection());
    
             Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,".-Module beginning");
payloadStr = new String(msg.getDocument().getContent(),"UTF-8");
    
            Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,"Payload before execution:" );
            Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,payloadStr );
             sep = moduleContext.getContextData(C_SEPARATOR_STRING);
             if ( sep == null ) {
                sep = C_AUX_SEPARATOR;
                Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,"Default separator used: " + sep);
             }
             else {
                Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,"Separator found: " + sep);
             }
    
   
    
             paramList = moduleContext.getContextDataKeys();
               while( paramList.hasMoreElements()) {
                    paramKey = (String) paramList.nextElement();
                 //Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,"ParamKey: " + paramKey);
                 param =  moduleContext.getContextData(paramKey);
                 //Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,"Param: " + param);
        
                 if ( ! paramKey.equals(C_SEPARATOR_STRING) && ! paramKey.equals(C_MODULEKEY_STRING) ){
                    Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,"ParamKey: " + paramKey);
                    Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,"Parameter: " + param);
                    Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,"Separator: " + sep);
           
                    strArray = param.split(sep);
                    if (strArray != null){
                       if ((! strArray[0].equals(null)) && (! strArray[1].equals(null))){
                        if ( strArray[1].equals(C_BLANK_STRING)){
                            Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,"Blank String");
                            strArray[1]=" ";                   
                        }
                        else if (strArray[1].equals(C_EMPTY_STRING)){
                            strArray[1]="";
                            Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,"Empty String");
                        }
                        Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,"Substitution strArray[0]: " + strArray[0]);
                        Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,"Substitution strArray[1]: " + strArray[1]);
                        Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,"Substitution payloadStrA : " + payloadStr);   
                        payloadStr = payloadStr.replaceAll(strArray[0],strArray[1]);
                        Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,"Substitution payloadStrB : " + payloadStr);
                       }
                    }
                 }
             }
             Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,"Payload after replacement:" );
             Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS,payloadStr );
   
             payloadOut = new ByteArrayOutputStream();
             payloadOut.write(payloadStr.getBytes());
             msg.getDocument().setContent(payloadOut.toByteArray());
             inputModuleData.setPrincipalData(msg);
        }
        catch(Exception e) {
            ModuleException me = new ModuleException(e);
            throw me;
        }
        return inputModuleData;
    }
}







To report this post you need to login first.

21 Comments

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

  1. Roger Allue Post author

    Hello Aaron,

    It seems something’s wrong with your ear.  Could you please tell me how are you deploying you ear?  You can check if the module is correctly deployed from the perspective Deployment of NWDS. On left panel you should see that the module is running (in green).

    Regards !

    (0) 
    1. Aaron Myers

      Hi, I think the Ear is deployed OK now. However in RWB com channel monitor I get error: “Message processing failed. Cause: java.lang.ArrayIndexOutOfBoundsException: 1″

      Does this perhaps mean my module parameters are maybe wrong? I tried with single quotes around the replace strings also. Is there a way to set breakpoint in NWDS or simulate the execution at runtime?

      /wp-content/uploads/2015/02/replacestringbean_644181.png

      12.02.2015 17:31:35.788 Information MP: entering1
      12.02.2015 17:31:35.790 Information .-Module beginning
      12.02.2015 17:31:35.790 Information MP: processing local module localejbs/ReplaceString
      12.02.2015 17:31:36.017 Information <ns0:MyMessage> … [contents omitted] … </ns0:MyMessage>
      12.02.2015 17:31:36.017 Information ParamKey: param1
      12.02.2015 17:31:36.017 Information Parameter: ns0;foobar
      12.02.2015 17:31:36.017 Information Payload before execution:
      12.02.2015 17:31:36.017 Information Separator found: ;
      12.02.2015 17:31:36.017 Information Separator: ;
      12.02.2015 17:31:36.018 Error MP: exception caught with cause java.lang.ArrayIndexOutOfBoundsException: 1
      12.02.2015 17:31:36.019 Error Adapter Framework caught exception: 1
      12.02.2015 17:31:36.020 Error Delivering the message to the application using connection File_http://sap.com/xi/XI/System failed, due to: com.sap.engine.interfaces.messaging.api.exception.MessagingException: java.lang.ArrayIndexOutOfBoundsException: 1.
      12.02.2015 17:31:36.025 Information The asynchronous message was successfully scheduled to be delivered at Thu Feb 12 17:36:36 CET 2015.
      12.02.2015 17:31:36.025 Information The message status was set to WAIT.
      (0) 
      1. Aaron Myers

        Think I found the issue here is with the separator. If I use ‘;’ in the config I get ArrayIndexOutOfBounds, but if I do not quote it in config it sends the message through the module OK.

        (0) 
      2. Aaron Myers

        I had only one other issue but solved it myself.

        On lines 137, 138 Java replaceAll was not making the substitution until I converted the String Arrays to regular Strings using .toString() method. After that with the same parameters it started to work. This could maybe be down to our old java version? I saw from your document you use the latest and greatest.

        Thanks so much Roger for posting this document and giving me some hints!!! I now have a basic understanding of how to write and deploy adapter modules.

        (0) 
  2. Midhun Madhav

    Hi Roger

    I am doing a REST — PI — ECC synchronous scenario. The xml payload is converted to JSON by REST channel and this causes an unwanted backward slash to be added to the payload.

    like this

    http://host:port/RESTAdapter/xyz

    becomes

    http:\/\/host:port\/RESTAdapter\/xyz


    is there any module that can remove the backward slash from the target payload


    Regards


    Midhun

    (0) 
    1. Roger Allue Post author

      Hello Midhun,


      Sorry, but I didn’t use the REST Adapter yet. However, If the URL is added to the payload you can always use my module.


      Just to understand a bit more the problem, could you please paste an example of your payload?



      Regards!

      (0) 
      1. Midhun Madhav

        Hi Roger

        This is the payload:

        {

           “MT_EmployeeNumber_CRN_Response_Receiver”: {

             “EmployeeNumberTable”: [

               {

                 “EmployeeNumber”: “134541”,

                 “EmployeeName”: Mark,

                 “EmployeeDescription”: “TEST 123”,

                 “EmployeeGroup”: “SAP”,

                 “links”: {

                   “self”: {

                     “href”:

        “http:\/\/host:port\/RESTAdapter\/CRN\/EmployeeNumber\/134541”

                   }

                 }

               },

             ]

           }

        }

        This payload is converted from xml to JSON. When the conversion is done an additional backward slash is added in front of all the forward slashes in the url.

        This is a synchronous scenarios, REST adapter at sender side and SOAP adapter at receiver side.

        My requirement is to take the backward slash from the JSON Payload

        Midhun

        (0) 
        1. Roger Allue Post author

          Hello Midhun,

          My module ReplaceString treats the payload as text, so it shouldn’t distinguish between xml and json messages. Notice that the module uses the java method replaceAll. This method expects a regular expression and you should escape backslashes.

          Could you configure the module with the following parameters?

          param1=\\/;/

          separator=;

          Regards!

          (0) 
          1. Roger Allue Post author

            Look, I have created a simple class to test replaceAll method:

            import java.util.Scanner;

            public class Test {

               

               

                public static void main(String[] args) {

                   

                   

                    Scanner keyboard = new Scanner(System.in);

                   

                    System.out.println(“Enter String:”);

                    String str = keyboard.nextLine();

                    System.out.println(“Enter Str1:”);

                    String str1 = keyboard.nextLine();

                    System.out.println(“Enter Str2:”);

                    String str2 = keyboard.nextLine();

                   

                    String str3 = str.replaceAll(str1, str2);

                   

                    System.out.println(“Str: ” + str);

                    System.out.println(“Str1: ” + str1);

                    System.out.println(“Str2: ” + str2);

                    System.out.println(“Str3: ” + str3);

                   

                }

            }

            And this is the result with your original string and the parameters I mentioned above:

            Enter String:

            http:\/\/host:port\/RESTAdapter\/xyz

            Enter Str1:

            \\/

            Enter Str2:

            /

            Str: http:\/\/host:port\/RESTAdapter\/xyz

            Str1: \\/

            Str2: /

            Str3: http://host:port/RESTAdapter/xyz

            Regards!

            (0) 
            1. Midhun Madhav

              Thanks a lot for your time, Roger

              I am working on it and will update you. Your help was priceless and really appreciate the time you have taken to help me

              (0) 
  3. Stefan Grube

    Hi Roger,

    Thank you for sharing your module. I think this will be helpful in many scenarios.

    However, I have some doubts about following piece of code:

       while((inputByte = payloadIn.read()) != –1) { 

               payloadStr = payloadStr + (char) inputByte; 

       } 


    As payloadIn.read() provides a byte, and you change it to (char), this leads to errors for all multi-byte UTF-8 character. For example the German character ‘ä’ (hex c3 a4) would be transformed to ‘ä’


    I recommend using following code line:


         payloadStr = new String(msg.getDocument().getContent(),”UTF-8″);


    This is the proper way to tranform a byte array into a String.


    Regards

    Stefan

    (0) 
  4. Roger Allue Post author

    Hello Apu,

    there are plenty of blogs on how to create your own module. Don’t get me wrong, but there’s a difference between sharing knowledge and working for free.

    Good luck.

    (0) 

Leave a Reply