Purpose

Purpose of this document is to provide the main usage of Dynamic Configuration along with the implementation details for each usage with Java Mapping in SAP PI. Same concept can be used in Graphical Mapping with use of UDFs.


Introduction

As the name suggests, the Dynamic Configuration in SAP PI is to set the attributes and properties at the runtime. The Dynamic Configuration object (com.sap.aii.mapping.api.DynamicConfiguration) is basically a map containing key value pair of adapter specific message attributes and custom attributes. It associates keys (DynamicConfigurationKeys) with string values.


Usages

Following are the main usages of Dynamic Configuration

  1. To set Adapter Specific Message Properties
  2. To create a common Java Mapping for Synchronous Scenario
  3. To pass on the request parameter to response mapping in Synchronous Scenario

Implementation

The implementation detail of each usage is explained below:

1. To set Adapter Specific Message Properties

SAP PI 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. These parameters are very important for fulfilling the business requirements.


E.g. For File Receiver Adapter, the most common requirement is to create the file with dynamic file name and also sometime in a directory which needs to be decided at runtime. Dynamic Configuration provides the most powerful solution to this problem (Variable Substitution is another method, but it has some limitations).


Following is the code to set the file name and directory dynamically with use of Java Mapping/UDFs, check the comments in the code for the understanding:


package xyz.eai.common;

import java.io.BufferedReader;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.Reader;

import java.text.SimpleDateFormat;

import java.util.Date;

import com.sap.aii.mapping.api.AbstractTransformation;

import com.sap.aii.mapping.api.DynamicConfiguration;

import com.sap.aii.mapping.api.DynamicConfigurationKey;

import com.sap.aii.mapping.api.StreamTransformationException;

import com.sap.aii.mapping.api.TransformationInput;

import com.sap.aii.mapping.api.TransformationOutput;

public class PassThrough extends AbstractTransformation{

      // Dynamic Configuration Key for the target file name which will be used in Receiver Adapter

      private static final DynamicConfigurationKey KEY_FILENAME = DynamicConfigurationKey.create(http://sap.com/xi/XI/System/File, “FileName”);

      // Dynamic Configuration Key for the target Directory name which will be used in Receiver Adapter

      private static final DynamicConfigurationKey KEY_DIRECTORY = DynamicConfigurationKey.create(http://sap.com/xi/XI/System/File, “Directory”);

      public void transform(TransformationInput arg0, TransformationOutput arg1)

      throws StreamTransformationException {

        String strFileName = “”;

        String strDirectory = “”;

        String strIDocNbr = “”; // to be retrieved from input data

        String strDataType = “”; // to be derived based on the input data

        String strDateTime = (new SimpleDateFormat(“ddMMyyyyHHmmss”)).format(new Date());

            try {

                  // Retrieve Data from the input steam

              InputStream is = arg0.getInputPayload().getInputStream();

              String strInData = convertStreamToString(is);

              /*

               * Implement necessary Business Logic here

               */

              // Create Dynamic Configuration Object

              DynamicConfiguration conf = arg0.getDynamicConfiguration();

            strFileName = “TARGET”+strIDocNbr+“-“+strDataType+“-“+strDateTime+“.xml”;

            strDirectory = “/apps/data/”+strDataType+“/in”;

            // Put the Key and Value in the Dynamic Configuration Object

            conf.put(KEY_FILENAME, strFileName);

            conf.put(KEY_DIRECTORY, strDirectory);

            // Write the data in the output stream

arg1.getOutputPayload().getOutputStream().write(strInData.toString().getBytes(“UTF-8”));

            } catch (Exception e) {

            }

       

      }

      public String convertStreamToString(InputStream in) {

            StringBuffer sb = new StringBuffer();

            try {

                  InputStreamReader isr = new InputStreamReader(in);

                  Reader reader = new BufferedReader(isr);

                  int ch;

                  while ((ch = in.read()) > -1)

                        sb.append((char) ch);

                  reader.close();

            } catch (Exception exception) {

            }

            return sb.toString();

      }

}

2. To create a common Java Mapping for Synchronous Scenario

In case of Synchronous scenarios it is required to create two mappings – Request data mapping and Response data mapping. With help of Dynamic Configuration, you can create only one Java Class which will have mapping for both request data and response data. This reduces the developmentand maintenance efforts significantly.

The Key-Value set in Dynamic Configuration helps in identifying whether to map request data or response data. The basic thing is that the Key-Value set in Dynamic Configuration during request mapping becomes available even in the response mapping.

Below is the sample Java Class which can be selected as the Request Java Mapping and Response Java Mapping in the Operation Mapping in ESR. Check the code comments to understand the concept.

package xyz.eai.common;

import java.io.BufferedReader;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.Reader;

import com.sap.aii.mapping.api.AbstractTransformation;

import com.sap.aii.mapping.api.DynamicConfiguration;

import com.sap.aii.mapping.api.DynamicConfigurationKey;

import com.sap.aii.mapping.api.StreamTransformationException;

import com.sap.aii.mapping.api.TransformationInput;

import com.sap.aii.mapping.api.TransformationOutput;

public class SynchronousMapping extends AbstractTransformation {

      // Dynamic Configuration Key for the identification whether the mapping is called for Request data or for Response Data

      private static final DynamicConfigurationKey KEY_STEP = DynamicConfigurationKey.create(http://sap.com/xi/XI/System/Custom, “Step”);

      @Override

      public void transform(TransformationInput arg0, TransformationOutput arg1)

                  throws StreamTransformationException {

            ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();

            String strStep = “”;

            try {

                  getTrace().addInfo(“Starting the Processing”);

            Thread.currentThread().setContextClassLoader(getClass().getClassLoader());

              // Retrieve Dynamic Configuration Object from Sender and Receiver adapter

            DynamicConfiguration conf = arg0.getDynamicConfiguration();

            // Get the Custom Key which will be null for Request Mapping and “1” for Response Mapping

            strStep = conf.get(KEY_STEP);

            this.getTrace().addInfo(“KEY_STEP: “ + strStep);

            // Decide the mapping based on value of Custom Key

            if (strStep != null && strStep.equals(“1”)) {

                  // Sub Method for Response Data Mapping

                  transformResponse(arg0, arg1, conf);

            } else {

                  // Sub Method for Request Data Mapping

                  transformRequest(arg0, arg1, conf);

                  conf.put(KEY_STEP, “1”);

            }

            } catch (Exception e) {

                  this.getTrace().addInfo((new StringBuilder(“Exception: “)).append(e.getMessage()).toString(), e);

            } finally {

                  Thread.currentThread().setContextClassLoader(oldLoader);

            }

      }

      public void transformRequest(TransformationInput arg0, TransformationOutput arg1, DynamicConfiguration conf)

      throws Exception {

            // Retrieve Request Data from the input steam of Sender Adapter

        InputStream is = arg0.getInputPayload().getInputStream();

        String strInData = convertStreamToString(is);

        String strOutData = “”;

        /*

         * Do the Request Data Mapping here

         */

        // Send the data to Receiver Adapter

arg1.getOutputPayload().getOutputStream().write(strOutData.toString().getBytes(“UTF-8”));

arg1.getOutputPayload().getOutputStream().flush();

      }

      public void transformResponse(TransformationInput arg0, TransformationOutput arg1, DynamicConfiguration conf)

      throws Exception {

            // Retrieve Response Data from the input steam of Receiver Adapter

        InputStream is = arg0.getInputPayload().getInputStream();

        String strInData = convertStreamToString(is);

        String strOutData = “”;

        /*

         * Do the Response Data Mapping here

         */

        // Send the data to Sender Adapter

arg1.getOutputPayload().getOutputStream().write(strOutData.toString().getBytes(“UTF-8”));

        arg1.getOutputPayload().getOutputStream().flush();

      }

 

      public String convertStreamToString(InputStream in) {

            StringBuffer sb = new StringBuffer();

            try {

                  InputStreamReader isr = new InputStreamReader(in);

                  Reader reader = new BufferedReader(isr);

                  int ch;

                  while ((ch = in.read()) > -1)

                        sb.append((char) ch);

                  reader.close();

            } catch (Exception exception) {

            }

            return sb.toString();

      }

}

3. To pass on the request parameter to response mapping in Synchronous Scenario

Many times in the synchronous integration scenarios with RFC Adapter, SOAP Adapter or even JDBC Adapter at the receiver side, the adapter response does not send back all the data which are passed as a part of request. But the final response needs to the Sender adapter needs some data from the request data.

For example, customer id is passed in the RFC/SOAP request, but the response doesn’t have the customer id back. And the final response to sender adapter needs customer id along with other details.

The Dynamic Configuration becomes handy to send parameters from request mapping to response mapping. All the Key-Values which are set in Request Mapping become available in the Response Mapping. Here no need to do any module configuration or anything else.

Below are the sample Java Mapping which is similar to usage 2. Here the Customer Id is retrieved in request mapping and utilized in response mapping. Check the comments in the code for the understanding.


package xyz.eai.common;

import java.io.BufferedReader;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.Reader;

import com.sap.aii.mapping.api.AbstractTransformation;

import com.sap.aii.mapping.api.DynamicConfiguration;

import com.sap.aii.mapping.api.DynamicConfigurationKey;

import com.sap.aii.mapping.api.StreamTransformationException;

import com.sap.aii.mapping.api.TransformationInput;

import com.sap.aii.mapping.api.TransformationOutput;

public class RequestResponseMapping extends AbstractTransformation {

      // Dynamic Configuration Key for the identification whether the mapping is called for Request data or for Response Data

      private static final DynamicConfigurationKey KEY_STEP = DynamicConfigurationKey.create(http://sap.com/xi/XI/System/Custom, “Step”);

      // Dynamic Configuration Key for the request data to be made available in response

      private static final DynamicConfigurationKey KEY_CUSTID = DynamicConfigurationKey.create(http://sap.com/xi/XI/System/Custom, “CustomerId”);

      @Override

      public void transform(TransformationInput arg0, TransformationOutput arg1)

                  throws StreamTransformationException {

            ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();

            String strStep = “”;

            try {

                  getTrace().addInfo(“Starting the Processing”);

            Thread.currentThread().setContextClassLoader(getClass().getClassLoader());

              // Retrieve Dynamic Configuration Object from Sender and Receiver adapter

            DynamicConfiguration conf = arg0.getDynamicConfiguration();

            // Get the Custom Key which will be null for Request Mapping and “1” for Response Mapping

            strStep = conf.get(KEY_STEP);

            this.getTrace().addInfo(“KEY_STEP: “ + strStep);

            // Decide the mapping based on value of Custom Key

            if (strStep != null && strStep.equals(“1”)) {

                  // Sub Method for Response Data Mapping

                  transformResponse(arg0, arg1, conf);

            } else {

                  // Sub Method for Request Data Mapping

                  transformRequest(arg0, arg1, conf);

                  conf.put(KEY_STEP, “1”);

            }

            } catch (Exception e) {

                  this.getTrace().addInfo((new StringBuilder(“Exception: “)).append(e.getMessage()).toString(), e);

            } finally {

                  Thread.currentThread().setContextClassLoader(oldLoader);

            }

      }

      public void transformRequest(TransformationInput arg0, TransformationOutput arg1, DynamicConfiguration conf)

      throws Exception {

            // Retrieve Request Data from the input steam of Sender Adapter

        InputStream is = arg0.getInputPayload().getInputStream();

        String strInData = convertStreamToString(is);

        String strCustId = “”; // To be retrieved from the request data

        String strOutData = “”;

        /*

         * Do the Request Data Mapping here

         */

        // Put the request parameter in the Dynamic Configuration

        conf.put(KEY_CUSTID, strCustId);

        // Send the data to Receiver Adapter

arg1.getOutputPayload().getOutputStream().write(strOutData.toString().getBytes(“UTF-8”));

arg1.getOutputPayload().getOutputStream().flush();

      }

      public void transformResponse(TransformationInput arg0, TransformationOutput arg1, DynamicConfiguration conf)

      throws Exception {

            // Retrieve ResponseData from the input steam of Receiver Adapter

        InputStream is = arg0.getInputPayload().getInputStream();

        String strInData = convertStreamToString(is);

        String strCustId = conf.get(KEY_CUSTID);

        this.getTrace().addInfo(“KEY_CUSTID: “ + strCustId);

        String strOutData = “”;

        /*

         * Do the Response Data Mapping here with data retrieved from Dynamic Configuration

         */

        // Send the data to Sender Adapter

arg1.getOutputPayload().getOutputStream().write(strOutData.toString().getBytes(“UTF-8”));

arg1.getOutputPayload().getOutputStream().flush();

      }

 

      public String convertStreamToString(InputStream in) {

            StringBuffer sb = new StringBuffer();

            try {

                  InputStreamReader isr = new InputStreamReader(in);

                  Reader reader = new BufferedReader(isr);

                  int ch;

                  while ((ch = in.read()) > -1)

                        sb.append((char) ch);

                  reader.close();

            } catch (Exception exception) {

            }

            return sb.toString();

      }

}

Same concept even work when the request mapping class and response mapping class are different. For the Graphical Mapping, UDFs can be leveraged to set and get the parameters to and from the Dynamic Configuration Object.

Java Docs

Refer the link below for the Java Docs of Dynamic Configuration in SAP PI 7.4:

https://help.sap.com/javadocs/NW74/SPS03/PI/com/sap/aii/mapping/api/DynamicConfiguration.html

To report this post you need to login first.

Be the first to leave a comment

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

Leave a Reply