Enterprise Master Data Management - A cross-system master data process for supplier

Applies to:

ERP 6 EhP5 – Master Data Governance for Supplier

Summary

This article provides implementation details for a simplified cross system Supplier On-boarding scenario leveraging SAP’s Enterprise Master Data Management portfolio consisting of SAP NetWeaver Master Data Management (available since 2004) and SAP Master Data Governance (currently in Ramp-Up). The overarching process is modeled using SAP NetWeaver Business Process Management.

Author(s): 

Lars Rueter  
Company :    SAP AG, Germany   
Created on:    4. March 2011
Author(s) Bio
Mr. Rüter works at SAP in the area of SAP Master Data Governance. In the past 11 years at SAP he has held different positions in Asia Pacific and EMEA. He has extensive experience in SAP's Master Data Management product portfolio, Java Development and SAP NetWeaver Portal. Mr Rüter has been involved in a large number of SAP implementations worldwide.

Cross system create supplier process

In our example we will build a cross-system supplier self-service registration and approval process. A supplier registers via a website and enters some initial data such as company name, street, city and postal code. These global attributes are stored in NetWeaver MDM for further distribution to Non-SAP systems. When the supplier is approved by the master data specialist a change request is automatically generated in SAP Master Data Governance. A workflow in SAP Master Data governance ensures that all ERP specific attributes are maintained. After final approval in SAP Master Data Governance the new supplier is activated and distributed. After activation a notification is send to the original requester.


Figure 1: High-level process overview

In figure 2 below you see which systems are part of the process:

  • (A) SAP Master Data Governance – maintenance and distribution of ERP specific attributes
  • (B) SAP NetWeaver MDM - maintenance and distribution of global attributes
  • (C) NetWeaver CE – process runtime, process specific UIs, process worklist, web service consumption and provisioning
  • (D) NetWeaver Developer Studio – process designtime


Figure 2: System Landscape

As mentioned above the process was implemented using NetWeaver BPM for the design and execution of the cross-system process. But we also leverage the out-the-box governance process in Master Data Governance for maintenance of ERP specific attributes.


Figure 3: Technical process overview

The figure above provides a more technical process overview using the Business Process Modeling Notation (BPMN) notation from SAP NetWeaver BPM:

  • (1) The initial supplier registration web page triggers the start web-service of the BPM process
  • (2) The global attributes from the registration web-page are used to create a new supplier record in SAP NetWeaver MDM
  • (3) In this human interaction step a new supplier is being approved
  • (4) BPM calls a SAP Master Data Governance Web Service to create a change request with the initial supplier data. This also triggers a SAP Business Workflow in SAP Master Data Governance.
  • (5) This step in BPM is called an intermediate message event. The process waits for a message to come in from Master Data Governance before the flow commences. Early in the SAP Business Workflow process we have inserted a task to call BPM. In this call we transmit the ID of the change request.
  • (6) BPM uses the change request ID from SAP Master Data Governance to send an e-mail to the original requestor. The e-mail contains a link to the SAP Business Workflow log. Using this link the original requestor can monitor the status of the change request in MDG.
  • (7) After sending an e-mail the BPM process waits again for a message from SAP Master Data Governance. This time SAP Master Data Governance sends a message at the end of the SAP Business Workflow process and after the Supplier has been finally approved and activated. The message includes the final ID of the Business Partner in the primary persistence.
  • (8) The last step in the BPM process informs the original requestor that the new Business Partner has been created and activated.

Implementation Steps

Integration between NetWeaver MDM and BPM has already been sufficiently documented on SDN. In this section the focus is on the integration between SAP Master Data Governance and NetWeaver BPM. Therefore we look specifically at the three integration points numbered step 4, step 5 and step 7 in figure 3 above. In step 4 we show how the inbound communication to SAP Master Data Governance was realized using a standard Web Service. The steps 5 and 7 are technically very similar in the sense that they both use a web service client proxy to transmit process status information from the SAP Business Workflow back to SAP NetWeaver BPM.

Using the inbound Business Partner Web Service

The ESR Web Service used to create a Business Partner in our scenario is called BusinessPartnerSUITEBulkReplicateRequest_In. In order to leverage this Web Service to automatically create a change request and key-mapping in SAP Master Data Governance , the method INBOUND_PROCESSING of BAdI MDG_SE_BP_BULK_REPLRQ_IN in Enhancement Sport MDG_SE_SPOT_BPBUPA has to be implemented.

IF_MDG_SE_BP_BULK_REPLRQ_IN~INBOUND_PROCESSING

METHOD if_mdg_se_bp_bulk_replrq_in~inbound_processing.

DATA ls_user_setting TYPE mdg_user_proxy_setting.
DATA lt_user_setting TYPE mdg_user_proxy_setting_t.
DATA lv_crtype TYPE mdg_sup_change_req.

if in-message_header-business_scope-id-content = 'BPM'.

ls_user_setting-field_name = 'PROXY_PERSISTANCE'.
ls_user_setting-field_value = '1'.
APPEND ls_user_setting TO lt_user_setting.
ls_user_setting-field_name = 'SUPPLIER_CHANGE'.

SELECT SINGLE usmd_creq_type INTO lv_crtype FROM usmd1601 WHERE usmd_process = 'SUP1'.
*
ls_user_setting-field_value = lv_crtype.
APPEND ls_user_setting TO lt_user_setting.


CALL METHOD cl_mdg_bp_bupa_si_in=>if_mdg_upload_proxy~setup_for_file_upload
EXPORTING
iv_instance = 1
* IO_UPLOAD_DIALOG =
it_user_setting = lt_user_setting.

endif.


ENDMETHOD.



The code first checks the scope-id-element in the message header. The SAP Master Data Governance load will only continue if the scope-id-element is set to BPM. The proxy implementation of the inbound service uses the context of the SAP Master Data Governance-file-upload-framework to determine how the incoming data has to be processed. We use the enhancement spot to set the file upload framework context in such a way that the incoming data is stored in the SAP Master Data Governance staging area and a change request of type SUPPL01 (Create Supplier) is being created. If key-mapping information was send as part of the Web Service call, the key-mapping for the new supplier will automatically be updated.


The ABAP code in the Enhancement Sport looks for the first process type SUP1 in table USMD1601 and takes the change request type from that line. In our example LRDEMO will be selected as change request type when the web service is called (refer to table USMD1601 in figure 4 below). You may have to adapt the ABAP code to ensure your custom change request type (as defined in the following section _ Customizing the governance process_) is correctly assigned in the Enhancement Spot.






Figure 4: Table USMD1601


An example XML document to test the web service is attached to this wiki.






Test your scenario – Inbound Web Service


You should now test if the implementation is working. Using a Web Service test tool such as the SAP Web Service Navigator you can call the Web Service. After successful execution you should find a new change request in the POWER -List (Personal Object Work Entity Repository). You can access the POWER-List via the supplier role in SAP Master Data Governance.



Customizing the governance process


Your Web Service is working? Good! Your inbound connection to SAP Master Data Governance is now ready. Next we need to establish the outbound connection to NetWeaver BPM. In our example we extend the governance process for create supplier by two additional SAP Business Workflow tasks. Each of the two tasks sends a message to NetWeaver BPM.



Since we do not want to modify the SAP delivered workflow template and change request type, we first create a copies.





  • Look up the id of the workflow template for Create Supplier: Open MDG IMG activity Create Change Request Type and find the row with change request type SUPPL01 (Create Supplier). In the same row you find the workflow template id for this change request type.




  • Open the Workflow Builder (transaction swdd) and create a copy of the SAP delivered workflow template for Create Supplier (use the workflow template id from the previous step). Do not forget to save and activate you new workflow template.




  • In MDG IMG activity Create Change Request Type create a copy of the SAP delivered change request type SUPPL01 (Create Supplier). Assign the new workflow template id from the previous step to the new change request. In our example we have created a custom change request type LRDEMO which is linked to workflow template WS99900008 (Firgure 5 below).







Figure 5: IMG activity Create Change Request Type





  • In MDG IMG activity Define workflow step numbers create a copy of the rows from the SAP delivered workflow template for the create supplier workflow template. In your copied rows change the workflow template id to the id of your custom workflow template.







Figure 6: IMG activity Define Workflow Step Numbers





  • To ensure the receiver determination will work for your new change request type enhance the BRF+ table GET_AGENT. Start transaction BRF+ and search for MDG as shown in figure 7 below.







Figure 7: BRF+ Search


Navigate to the GET_AGENT table as shown in figure 8. Create one row in the table for each workflow step. In column CREQUEST_TYPE enter the name of your custom change request type. In columns OTYPE and OBJID enter the object type (eg. user / organization) and corresponding value respectively.






Figure 8: BRF+ table get_agent






Test your scenario – custom change request type


This a good point to test your new change request type and workflow template. From the supplier role menu in SAP Master Data Governance choose the Create Supplier menu item. You should see your custom change request type in the drop down box of the create supplier screen. Select your custom change request type. Enter the new business partner details and approve the individual workflow steps until activation. At the end of the workflow you should have created a new Business Partner in the primary persistence. You can check by doing a search for the business partner id. You may have to change the receiver determination in BRF+ to ensure you can approve all the workflow steps.






Test your scenario – inbound web service with custom change request type


If you have confirmed that your new change request type and workflow template are working, repeat the test using the BusinessPartnerSUITEBulkReplicateRequest_In web service. Verify that after calling the web service a change request is created and the associated custom workflow is started. You can use transaction swud to find the workflow instance.



Exchanging process context information between SAP Business Workflow and NetWeaver BPM


In our example we decided to implement the exchange of process context information between NetWeaver BPM and SAP Business Workflow using asynchronous web services. In particular for exchanging the MDG change request id and business partner id. In NetWeaver BPM two Trigger Events were created (wsdl1, wsdl2) for this purpose. The consumption side is technically realized by generating an ABAP proxy for each service and calling this proxy from a task in the SAP Business Workflow. In step 5 (figure 3) we are using the Web Service call to transfer the change request-id to the SAP NetWeaver BPM context. In step 7 (figure 3) we transfer the business partner id after activation in the back end. After transferring the change request id step 5 (figure 3) we can use the change request id in NetWeaver BPM to generate an URL to the SAP Business Workflow log for this change request. We use this URL in our BPM process to send an e-mail notification to the original requestor with the link to the workflow log.






Generating a SAP Business Workflow log URL from a change request id in SAP MDG


https:// <HOSTNAME> : <PORT> /sap/bc/webdynpro/sap/usmd_crequest_protocol2?SAP-CLIENT= <CLIENT> &SAP-LANGUAGE=EN&CREQUEST= <insert the change request number here>



For sending the change request id to NetWeaver BPM a task was added after the Set Initial Status of Change Request task at the beginning of the workflow (figure 9). In the object method section of the task maintenance screen (figure 10) a custom class and method is selected. The called method calls the web service proxy to transmit the change request id. To be able to select your custom class from the workflow task it must implement the interfaces BI_OBJECT, BI_PRESISTENT and IF_WORKFLOW (figure 13). You can find more information regarding ABAP OO for workflow in the references section at the bottom of the article.






Figure 9: Create business partner workflow with custom task






Figure 10: Custom task maintenance



For sending the change request id to NetWeaver BPM a task was added after the Set Initial Status of Change Request task at the beginning of the workflow (figure 9). In the object method section of the task maintenance screen (figure 10) a custom class and method is selected. The called method calls the web service proxy to transmit the change request id. To be able to select your custom class from the workflow task it must implement the interfaces BI_OBJECT, BI_PRESISTENT and IF_WORKFLOW (figure 13). You can find more information regarding ABAP OO for workflow in the references section at the bottom of the article.



After successful activation of the Business Partner we can send the Business Partner Id to NetWeaver BPM. A new task was created after the Set Status of Change Request close to the end of the process (figure 11). In the task maintenance (figure 12) we assign a custom method that in turn uses the web service proxy to call NetWeaver BPM.






Figure 11: Create business partner workflow with custom task






Figure 12: Custom task maintenance






Figure 13: Interface tab of the class that gets called from the custom workflow task






Test your scenario – complete process


You can now call the inbound SAP Master Data Governance web service. In turn a change request will be created. The change request id will be transmitted to NetWeaver BPM. After approval and activation of the Business Partner the Business Partner id is transmitted to NetWeaver BPM. You can use transaction sxi_monitor to view incoming and outgoing messages.



NetWeaver BPM implementation considerations


While the focus of this article is not so much on NetWeaver BPM, but more on the interfaces of SAP Master Data Governance one important aspect with regard to intermediate message events in NetWeaver BPM should be mentioned here. In NetWeaver BPM it is necessary to define a message correlation between the incoming messages from SAP Master Data Governance and the process instance in NetWeaver BPM. Any unique id (eg. process id) can be used for this purpose. The unique id can be send as part of the BusinessPartnerSUITEBulkReplicateRequest_In web service call, for example in the message header. Subsequent calls from SAP Master Data Governance to NetWeaver BPM can then transmit this unique id as part of the message payload. NetWeaver BPM uses the unique id to find the right process instance for the incoming message.



Summary



In this article it was shown how SAP Master Data Governance can be used as part of a NetWeaver BPM cross-system master data process. The article also highlights how the capabilities of the build in governance processes can be easily extended using SAP NetWeaver BPM. The combination of SAP Master Data Governance with SAP NetWeaver BPM and SAP NetWeaver Master Data Management addresses a wide range of scenarios in the area of Enterprise Master Data Management.

Search In a MDM Repository

Following code snippet shows the step to search inside MDM repository. It searches the string inside field Vendors in the table Vendors under repository Vendor1 .

public class Connection {     private SimpleConnection simpleConnection;     private String serverName = " ";     private String repositoryName="Vendor1";     private String dbServerName = " ";     private DBMSType dbmsType = DBMSType.MS_SQL;     private RegionProperties dataRegion = new RegionProperties();     private String userSession;     private String repositorySession;     private String userName="Admin";     private String password="mdm";     private RepositorySchema schema;     private RepositoryIdentifier repositoryID;     public void getConnection() {         try {             if (simpleConnection == null) {                 simpleConnection =                     SimpleConnectionFactory.getInstance(serverName);             }         } catch (Exception e) {             //              }     }         public void closeConnection( )       {         //@@begin closeConnection()         try{             if(simpleConnection!=null){                 DestroySessionCommand destroySessionCommand=new DestroySessionCommand(simpleConnection);                 destroySessionCommand.setSession(userSession);                 destroySessionCommand.execute();                 userSession=null;                 simpleConnection.close();             }         }catch(Exception e){
//                    }         //@@end       }           public void getAuthenticatedUserSession( )       {         //@@begin getAuthenticatedUserSession()         /*             * Create and authenticate a new user session to an MDM repository             */            repositoryID=new RepositoryIdentifier(repositoryName,dbServerName,dbmsType);            CreateUserSessionCommand createUserSessionCommand=new CreateUserSessionCommand(simpleConnection);            createUserSessionCommand.setRepositoryIdentifier(repositoryID);            createUserSessionCommand.setDataRegion(dataRegion);            try {                createUserSessionCommand.execute();                    userSession=createUserSessionCommand.getUserSession();// Get the session identifier               /* Authenticate User Session */            TrustedUserSessionCommand trustedUserSessionCommand=new TrustedUserSessionCommand(simpleConnection);            trustedUserSessionCommand.setUserName(userName);                      trustedUserSessionCommand.setSession(userSession);            try {                trustedUserSessionCommand.execute();                userSession=trustedUserSessionCommand.getSession();            } catch (CommandException e1) {                /* Trusted Connection is not accepted */                AuthenticateUserSessionCommand authenticateUserSessionCommand=new AuthenticateUserSessionCommand(simpleConnection);                authenticateUserSessionCommand.setSession(userSession);                authenticateUserSessionCommand.setUserName(userName);                authenticateUserSessionCommand.setUserPassword(password);                authenticateUserSessionCommand.execute();                    }                   SetUnicodeNormalizationCommand unicodeNormalizationCommand=new SetUnicodeNormalizationCommand(simpleConnection);            unicodeNormalizationCommand.setSession(userSession);            unicodeNormalizationCommand.setNormalizationType(SetUnicodeNormalizationCommand.NORMALIZATION_COMPOSED);            unicodeNormalizationCommand.execute();            }catch (CommandException e2) {
//                         }       }           public void setRegionProperties( )       {         //@@begin setRegionProperties()         dataRegion.setRegionCode("engUSA");         // Set the locale on data region         dataRegion.setLocale(new Locale("en", "US"));         // Set the name of data region         dataRegion.setName("US");         //@@end       }     public void setRepositoryInfo( java.lang.String repositoryName, java.lang.String userID, java.lang.String password )      {        //@@begin setRepositoryInfo()        this.repositoryName=repositoryName;        this.userName=userID;        this.password=password;            //@@end      }           public void getAuthenticatedRepositorySession( )     {       //@@begin getAuthenticatedRepositorySession()           try{               CreateRepositorySessionCommand repositorySessionCommand=new CreateRepositorySessionCommand(simpleConnection);               repositorySessionCommand.setRepositoryIdentifier(repositoryID);               repositorySessionCommand.execute();               repositorySession=repositorySessionCommand.getRepositorySession();                       AuthenticateRepositorySessionCommand authenticatedRepositorySession=new AuthenticateRepositorySessionCommand(simpleConnection);               authenticatedRepositorySession.setSession(repositorySession);               authenticatedRepositorySession.setUserName(userName);               authenticatedRepositorySession.setUserPassword(password);               authenticatedRepositorySession.execute();                       GetRepositorySchemaCommand repositroySchemaCommand=new GetRepositorySchemaCommand(simpleConnection);               repositroySchemaCommand.setSession(repositorySession);               repositroySchemaCommand.execute();               schema=repositroySchemaCommand.getRepositorySchema();                           }catch(CommandException e){
//                        }catch(Exception e){
//                        }               //@@end     }         public com.sap.mdm.ids.FieldId getFieldID( java.lang.String tableName, java.lang.String fieldCode )       {         //@@begin getFieldID()             return schema.getField(tableName,fieldCode).getId();             //@@end       }           public com.sap.mdm.ids.TableId getTableID( java.lang.String tableName )       {         //@@begin getTableID()         return schema.getTable(tableName).getId();         //@@end       }           public void searchRepository() {             //@@begin searchRepository()             ResultDefinition resultDef =                 new ResultDefinition(schema.getTable("Vendors").getId());             resultDef.addSelectField(schema.getField("Vendors", "Name").getId());             //resultDef.addSelectField(new FieldId(15));             FieldSearchDimension searchDimension =                 new FieldSearchDimension(                     schema.getField("Vendors", "Name").getId());             TextSearchConstraint constraint =                 new TextSearchConstraint("ABC", TextSearchConstraint.CONTAINS);             Search search = new Search(schema.getTable("Vendors").getId());             //search.addSearchItem(searchDimension,constraint);             RetrieveLimitedRecordsCommand limitedRecordsCommand =                 new RetrieveLimitedRecordsCommand(simpleConnection);             limitedRecordsCommand.setSearch(search);             limitedRecordsCommand.setSession(userSession);             limitedRecordsCommand.setResultDefinition(resultDef);             try {                 limitedRecordsCommand.execute();             } catch (CommandException e) {                 //                          }             //return limitedRecordsCommand.getRecords();             RecordResultSet recordSet = limitedRecordsCommand.getRecords();             String recordAsString = null;             String fieldValue = null;             for (int i = 0; i < recordSet.getCount(); i++) {                 recordAsString = "";                 FieldId[] returnedFields = recordSet.getRecord(i).getFields();                 for (int j = 0; j < returnedFields.length; j++) {                     if (recordSet                         .getRecord(i)                         .getFieldValue(returnedFields[j])                         .isNull()) {                         fieldValue = " |";                     } else {                         fieldValue =                             recordSet.getRecord(i).getFieldValue(returnedFields[j])                                 + "|";                     }                                         recordAsString += fieldValue;                     System.out.println(recordAsString);                 }             }         }                 public static void main (String[] args)                 {             Connection test=new Connection();             test.getConnection();             test.setRegionProperties();             test.setRepositoryInfo("Vendor1","Admin","mdm");             test.getAuthenticatedUserSession();             test.getAuthenticatedRepositorySession();             test.searchRepository();             test.closeconnection();              }

}

Code to Get List of Validation in a Table

Following code snippet finds out the list of Validation from a Table.

package com.sap.infosys.mdm.validationcheck;

import com.sap.mdm.commands.AuthenticateUserSessionCommand;
import com.sap.mdm.commands.CommandException;
import com.sap.mdm.commands.CreateUserSessionCommand;
import com.sap.mdm.commands.DestroySessionCommand;
import com.sap.mdm.commands.GetRepositoryRegionListCommand;
import com.sap.mdm.data.RegionProperties;
import com.sap.mdm.ids.TableId;
import com.sap.mdm.net.ConnectionException;
import com.sap.mdm.net.ConnectionPool;
import com.sap.mdm.net.ConnectionPoolFactory;
import com.sap.mdm.server.DBMSType;
import com.sap.mdm.server.RepositoryIdentifier;
import com.sap.mdm.validation.ValidationProperties;
import com.sap.mdm.validation.ValidationPropertiesResult;
import com.sap.mdm.validation.commands.RetrieveValidationsCommand;


public class GetListOfValidations {     public static void main(String[] args) {         // create connection pool to a MDM server         String serverName = " ";         ConnectionPool connections = null;         try {             connections = ConnectionPoolFactory.getInstance(serverName);         } catch (ConnectionException e) {             e.printStackTrace();             return;         }         // specify the repository to use         // alternatively, a repository identifier can be obtain from the GetMountedRepositoryListCommand         String repositoryName = "Vendor1";         String dbmsName = " ";         RepositoryIdentifier reposId =             new RepositoryIdentifier(repositoryName, dbmsName, DBMSType.MS_SQL);         // get list of available regions for the repository         GetRepositoryRegionListCommand regionListCommand =             new GetRepositoryRegionListCommand(connections);         regionListCommand.setRepositoryIdentifier(reposId);         try {             regionListCommand.execute();         } catch (CommandException e) {             e.printStackTrace();             return;         }         RegionProperties[] regions = regionListCommand.getRegions();         // create a user session         CreateUserSessionCommand sessionCommand =             new CreateUserSessionCommand(connections);         sessionCommand.setRepositoryIdentifier(reposId);         sessionCommand.setDataRegion(regions[0]); // use the first region         try {             sessionCommand.execute();         } catch (CommandException e) {             e.printStackTrace();             return;         }         String sessionId = sessionCommand.getUserSession();         // authenticate the user session         String userName = "Admin";         String userPassword = "mdm";         AuthenticateUserSessionCommand authCommand =             new AuthenticateUserSessionCommand(connections);         authCommand.setSession(sessionId);         authCommand.setUserName(userName);         authCommand.setUserPassword(userPassword);         try {             authCommand.execute();         } catch (CommandException e) {             e.printStackTrace();             return;         }         // the main table, hard-coded         TableId mainTableId = new TableId(1);         // Get the list of validations         RetrieveValidationsCommand objRtvVldCmd =             new RetrieveValidationsCommand(connections);         // set the user session         objRtvVldCmd.setSession(sessionId);         // get validation for the following tables.         objRtvVldCmd.setTableId(mainTableId);                 try {             objRtvVldCmd.execute();         } catch (CommandException e) {             e.printStackTrace();             return;         }         ValidationPropertiesResult objVldPropRslt =             objRtvVldCmd.getValidationPropertiesResult();         ValidationProperties[] validations = objVldPropRslt.getValidations();         //disply --> Validation ID | error/warning message | Validation Name         for (int i = 0; i < validations.length; i++) {             System.out.println(                 validations[i].getId()                     + " | "                     + validations[i].getMessage()                     + " | "                     + validations[i].getName());         }     }

}

A Class worth exploring for handling special characters in MDM

While development was going at full pace ,a small hurdle in form of special characters turned out to be a real speed breaker.The situtaion was that in MDM repository some field say Name contained  special chracters(Õ , û  ,Û)  in  other language like Hungarian,German ,French etc.Problem was I  logged into the Repository with english language with MDM JAVA API and  API was retrieving undesired value(O??,u??,U??) from the data manager .Although the Name string seems absolutely fine in the Data Manager.In short -value in MDM Data Manager for field name was Õ û  Û and output from API was O??u??U??

To my rescue came this class which is worth exploring when you have a situation like above

Class SetUnicodeNormalizationCommand

After you establish your connection to the server through API and Authenticate User Session ,you need to work with this class.

Connection to server would return an object of type ConnectionPool (call it connection)and UserSession authentication would return a string (call it session).Now write this piece of code

SetUnicodeNormalizationCommand cmd = new SetUnicodeNormalizationCommand(connection);

cmd.setSession(session);

cmd.setNormalizationType(SetUnicodeNormalizationCommand.NORMALIZATION_COMPOSED);

cmd.execute();

This class will keep the special characters retrieval intact.

SRM-MDM Catalog version compatibility

Purpose

The main objective of this page is to explain the compatibility between SRM-MDM Catalog, Java API and MDM Server.

Overview

The application SRM-MDM Catalog is dependent on other two main applications or components, which are MDM Server and MDM Java API. The compatibility of these applications is informed in the SRM-MDM Release Notes available in SAP Service Marketplace (Software Download Center):

https://service.sap.com/swdc

This document will present how to check the versions of each of these applications and it will also explain how to correct the compatibility in case there is a version mismatch.

Identifying the versions of your applications

You can get this information by accessing the J2EE component info page (http://<J2EE_SERVER>:<PORT>/sap/monitoring/ComponentInfo).

The Component name of SRM-MDM is SRM_MDM_CAT and the Component name of MDM Java API is MDM_JAVA_API.

In order to get the information of your MDM Server, please follow the steps below:

1) Open the SRM MDM utilities:

http://<J2EE_SERVER>:<PORT>/webdynpro/dispatcher/sap.com/tc~mdm~srmcat~uiutil/Utilities

2) Choose "Connection Test"

3) Provide the host name or IP of your MDM server (MDM server)

4) Click on "Start Testing" button

Checking the compatibility of your applications

Find the latest release note according to your SRM-MDM Support Package (SP) and open this note.

You will find in the note the SRM-MDM Catalog SP and Patch as well as the MDM Server SP. The version of MDM Java API should be the same as MDM Server since they are distributed together, as part of the same release.

See the image below for more information:

If the version of these three components is not compatible then it is probable that you will face issues during the usage of SRM-MDM Catalog.

Example of compatible versions:

SAP Note 1505367 mention SRM-MDM Catalog 3.0 SP08 Patch 01 is compatible with MDM Server 7.1 SP05.

Your component versions:

SRM_MDM_CAT:3.0 SP8 (1000.3.0.8.123.123456789)

MDM_JAVA_API: 710 SP5 (1000.710.0.5.123.123456789)

MDM Server: MDM Server 7.1 SP5 (Check)

Example of incompatible versions:

SAP Note 1642907 mention SRM-MDM Catalog 3.0 SP11 Patch 01 is compatible with MDM Server 7.1 SP07.

Your component versions:

SRM_MDM_CAT:3.0 SP11 (1000.3.0.8.123.123456789)

MDM_JAVA_API: 710 SP4 (1000.710.0.4.123.123456789)

MDM Server: MDM Server 7.1 SP4 (Check)

Solving the incompatibility of your applications

In case you have a version mismatch you should update your applications according to the latest release note for SRM-MDM. In case you don’t want to update your MDM Server than use the latest release note according to your SRM-MDM SP. Note that some errors are corrected in higher releases so it is not guaranteed that your issue will be solved by updating to the latest release of your SP. 

In order to update your application components go to Software Download Center, click on "Support Packages and Patches" (top menu) and then click on "Search for Support Packages and Patches" (left menu). Search for "SAP MDM CATALOG" and click on oyr SRM-MDM version. For more information please check note 1476694.

Related Content

Related Documents

Related Notes

SAP Note: 1650896 - SRM-MDM “Login Failed” error

SAP Note: 1476694 - Change in SRM-MDM Catalog 3.0 components in SMP

SAP Note: 1663002 - SRM-MDM Catalog "Repository Locked"

Code to Get List of Validation in a Table

Following code snippet finds out the list of Validation from a Table.

package com.sap.infosys.mdm.validationcheck;

import com.sap.mdm.commands.AuthenticateUserSessionCommand;
import com.sap.mdm.commands.CommandException;
import com.sap.mdm.commands.CreateUserSessionCommand;
import com.sap.mdm.commands.DestroySessionCommand;
import com.sap.mdm.commands.GetRepositoryRegionListCommand;
import com.sap.mdm.data.RegionProperties;
import com.sap.mdm.ids.TableId;
import com.sap.mdm.net.ConnectionException;
import com.sap.mdm.net.ConnectionPool;
import com.sap.mdm.net.ConnectionPoolFactory;
import com.sap.mdm.server.DBMSType;
import com.sap.mdm.server.RepositoryIdentifier;
import com.sap.mdm.validation.ValidationProperties;
import com.sap.mdm.validation.ValidationPropertiesResult;
import com.sap.mdm.validation.commands.RetrieveValidationsCommand;


public class GetListOfValidations {     public static void main(String[] args) {         // create connection pool to a MDM server         String serverName = " ";         ConnectionPool connections = null;         try {             connections = ConnectionPoolFactory.getInstance(serverName);         } catch (ConnectionException e) {             e.printStackTrace();             return;         }         // specify the repository to use         // alternatively, a repository identifier can be obtain from the GetMountedRepositoryListCommand         String repositoryName = "Vendor1";         String dbmsName = " ";         RepositoryIdentifier reposId =             new RepositoryIdentifier(repositoryName, dbmsName, DBMSType.MS_SQL);         // get list of available regions for the repository         GetRepositoryRegionListCommand regionListCommand =             new GetRepositoryRegionListCommand(connections);         regionListCommand.setRepositoryIdentifier(reposId);         try {             regionListCommand.execute();         } catch (CommandException e) {             e.printStackTrace();             return;         }         RegionProperties[] regions = regionListCommand.getRegions();         // create a user session         CreateUserSessionCommand sessionCommand =             new CreateUserSessionCommand(connections);         sessionCommand.setRepositoryIdentifier(reposId);         sessionCommand.setDataRegion(regions[0]); // use the first region         try {             sessionCommand.execute();         } catch (CommandException e) {             e.printStackTrace();             return;         }         String sessionId = sessionCommand.getUserSession();         // authenticate the user session         String userName = "Admin";         String userPassword = "mdm";         AuthenticateUserSessionCommand authCommand =             new AuthenticateUserSessionCommand(connections);         authCommand.setSession(sessionId);         authCommand.setUserName(userName);         authCommand.setUserPassword(userPassword);         try {             authCommand.execute();         } catch (CommandException e) {             e.printStackTrace();             return;         }         // the main table, hard-coded         TableId mainTableId = new TableId(1);         // Get the list of validations         RetrieveValidationsCommand objRtvVldCmd =             new RetrieveValidationsCommand(connections);         // set the user session         objRtvVldCmd.setSession(sessionId);         // get validation for the following tables.         objRtvVldCmd.setTableId(mainTableId);                 try {             objRtvVldCmd.execute();         } catch (CommandException e) {             e.printStackTrace();             return;         }         ValidationPropertiesResult objVldPropRslt =             objRtvVldCmd.getValidationPropertiesResult();         ValidationProperties[] validations = objVldPropRslt.getValidations();         //disply --> Validation ID | error/warning message | Validation Name         for (int i = 0; i < validations.length; i++) {             System.out.println(                 validations[i].getId()                     + " | "                     + validations[i].getMessage()                     + " | "                     + validations[i].getName());         }     }

CreateRecordCommand Vs CreateRecordsCommand

Given the shortcomings of Import Manager of rejecting a complete input excel spreadsheet, in case of even a single spurious record and lack of comprehensive error reporting to track reasons for file rejection or all errors. All these and more combined together, gave me a reason to develop a prototype, which overcomes shortcomings of using Import Manager to import data into MDM repository using Excel spreadsheets

In this blog I will discuss two important API classes, CreateRecordCommand and CreateRecordsCommand , and in following blogs will detail the complete design using which you can have your own customised Import Manager, capable of Importing data from excel spreadsheet into MDM repository with comprehensive error reporting.

Browsing through the MDM Java API documentation I found two classes for creating records in the repository:

  • CreateRecordCommand &
  • CreateRecordsCommand

While the first command is used to create individual records in the repository, the following CreateRecordsCommand is used for mass record creation.

It is a single Record Object which is a required parameter for CreateRecordCommand, we need to set an array of Record objects (records for mass creation) for CreateRecordsCommand.

Using CreateRecordCommand you can get 'recordId' of the newly created record but using CreateRecordsCommand the API provides us various methods to retrieve

  • FailedRecordMessages
  • Succeeded Record recordIds
  • Failed and Succeeded Record Arrays, containing corresponding indexes in the records array initially passed into CreateRecordsCommand
  • Array of all records passed into CreateRecordsCommand

Please use the link of MDM Java API javadoc link http://help.sap.com/javadocs/MDM/SP06P2/index.html to find out specific methods for CreateRecordsCommand, which can be used to retrieve specific information in order to generate better reports with exception/error messages.

Signing off for now....... till my next page in this series.

Search In a MDM Repository

Following code snippet shows the step to search inside MDM repository. It searches the string inside field Vendors in the table Vendors under repository Vendor1 .

public class Connection {     private SimpleConnection simpleConnection;     private String serverName = " ";     private String repositoryName="Vendor1";     private String dbServerName = " ";     private DBMSType dbmsType = DBMSType.MS_SQL;     private RegionProperties dataRegion = new RegionProperties();     private String userSession;     private String repositorySession;     private String userName="Admin";     private String password="mdm";     private RepositorySchema schema;     private RepositoryIdentifier repositoryID;     public void getConnection() {         try {             if (simpleConnection == null) {                 simpleConnection =                     SimpleConnectionFactory.getInstance(serverName);             }         } catch (Exception e) {             //              }     }         public void closeConnection( )       {         //@@begin closeConnection()         try{             if(simpleConnection!=null){                 DestroySessionCommand destroySessionCommand=new DestroySessionCommand(simpleConnection);                 destroySessionCommand.setSession(userSession);                 destroySessionCommand.execute();                 userSession=null;                 simpleConnection.close();             }         }catch(Exception e){
//                    }         //@@end       }           public void getAuthenticatedUserSession( )       {         //@@begin getAuthenticatedUserSession()         /*             * Create and authenticate a new user session to an MDM repository             */            repositoryID=new RepositoryIdentifier(repositoryName,dbServerName,dbmsType);            CreateUserSessionCommand createUserSessionCommand=new CreateUserSessionCommand(simpleConnection);            createUserSessionCommand.setRepositoryIdentifier(repositoryID);            createUserSessionCommand.setDataRegion(dataRegion);            try {                createUserSessionCommand.execute();                    userSession=createUserSessionCommand.getUserSession();// Get the session identifier               /* Authenticate User Session */            TrustedUserSessionCommand trustedUserSessionCommand=new TrustedUserSessionCommand(simpleConnection);            trustedUserSessionCommand.setUserName(userName);                      trustedUserSessionCommand.setSession(userSession);            try {                trustedUserSessionCommand.execute();                userSession=trustedUserSessionCommand.getSession();            } catch (CommandException e1) {                /* Trusted Connection is not accepted */                AuthenticateUserSessionCommand authenticateUserSessionCommand=new AuthenticateUserSessionCommand(simpleConnection);                authenticateUserSessionCommand.setSession(userSession);                authenticateUserSessionCommand.setUserName(userName);                authenticateUserSessionCommand.setUserPassword(password);                authenticateUserSessionCommand.execute();                    }                   SetUnicodeNormalizationCommand unicodeNormalizationCommand=new SetUnicodeNormalizationCommand(simpleConnection);            unicodeNormalizationCommand.setSession(userSession);            unicodeNormalizationCommand.setNormalizationType(SetUnicodeNormalizationCommand.NORMALIZATION_COMPOSED);            unicodeNormalizationCommand.execute();            }catch (CommandException e2) {
//                         }       }           public void setRegionProperties( )       {         //@@begin setRegionProperties()         dataRegion.setRegionCode("engUSA");         // Set the locale on data region         dataRegion.setLocale(new Locale("en", "US"));         // Set the name of data region         dataRegion.setName("US");         //@@end       }     public void setRepositoryInfo( java.lang.String repositoryName, java.lang.String userID, java.lang.String password )      {        //@@begin setRepositoryInfo()        this.repositoryName=repositoryName;        this.userName=userID;        this.password=password;            //@@end      }           public void getAuthenticatedRepositorySession( )     {       //@@begin getAuthenticatedRepositorySession()           try{               CreateRepositorySessionCommand repositorySessionCommand=new CreateRepositorySessionCommand(simpleConnection);               repositorySessionCommand.setRepositoryIdentifier(repositoryID);               repositorySessionCommand.execute();               repositorySession=repositorySessionCommand.getRepositorySession();                       AuthenticateRepositorySessionCommand authenticatedRepositorySession=new AuthenticateRepositorySessionCommand(simpleConnection);               authenticatedRepositorySession.setSession(repositorySession);               authenticatedRepositorySession.setUserName(userName);               authenticatedRepositorySession.setUserPassword(password);               authenticatedRepositorySession.execute();                       GetRepositorySchemaCommand repositroySchemaCommand=new GetRepositorySchemaCommand(simpleConnection);               repositroySchemaCommand.setSession(repositorySession);               repositroySchemaCommand.execute();               schema=repositroySchemaCommand.getRepositorySchema();                           }catch(CommandException e){
//                        }catch(Exception e){
//                        }               //@@end     }         public com.sap.mdm.ids.FieldId getFieldID( java.lang.String tableName, java.lang.String fieldCode )       {         //@@begin getFieldID()             return schema.getField(tableName,fieldCode).getId();             //@@end       }           public com.sap.mdm.ids.TableId getTableID( java.lang.String tableName )       {         //@@begin getTableID()         return schema.getTable(tableName).getId();         //@@end       }           public void searchRepository() {             //@@begin searchRepository()             ResultDefinition resultDef =                 new ResultDefinition(schema.getTable("Vendors").getId());             resultDef.addSelectField(schema.getField("Vendors", "Name").getId());             //resultDef.addSelectField(new FieldId(15));             FieldSearchDimension searchDimension =                 new FieldSearchDimension(                     schema.getField("Vendors", "Name").getId());             TextSearchConstraint constraint =                 new TextSearchConstraint("ABC", TextSearchConstraint.CONTAINS);             Search search = new Search(schema.getTable("Vendors").getId());             //search.addSearchItem(searchDimension,constraint);             RetrieveLimitedRecordsCommand limitedRecordsCommand =                 new RetrieveLimitedRecordsCommand(simpleConnection);             limitedRecordsCommand.setSearch(search);             limitedRecordsCommand.setSession(userSession);             limitedRecordsCommand.setResultDefinition(resultDef);             try {                 limitedRecordsCommand.execute();             } catch (CommandException e) {                 //                          }             //return limitedRecordsCommand.getRecords();             RecordResultSet recordSet = limitedRecordsCommand.getRecords();             String recordAsString = null;             String fieldValue = null;             for (int i = 0; i < recordSet.getCount(); i++) {                 recordAsString = "";                 FieldId[] returnedFields = recordSet.getRecord(i).getFields();                 for (int j = 0; j < returnedFields.length; j++) {                     if (recordSet                         .getRecord(i)                         .getFieldValue(returnedFields[j])                         .isNull()) {                         fieldValue = " |";                     } else {                         fieldValue =                             recordSet.getRecord(i).getFieldValue(returnedFields[j])                                 + "|";                     }                                         recordAsString += fieldValue;                     System.out.println(recordAsString);                 }             }         }                 public static void main (String[] args)                 {             Connection test=new Connection();             test.getConnection();             test.setRegionProperties();             test.setRepositoryInfo("Vendor1","Admin","mdm");             test.getAuthenticatedUserSession();             test.getAuthenticatedRepositorySession();             test.searchRepository();             test.closeconnection();              }

}

A Class worth exploring for handling special characters in MDM

While development was going at full pace ,a small hurdle in form of special characters turned out to be a real speed breaker.The situtaion was that in MDM repository some field say Name contained  special chracters(Õ , û  ,Û)  in  other language like Hungarian,German ,French etc.Problem was I  logged into the Repository with english language with MDM JAVA API and  API was retrieving undesired value(O??,u??,U??) from the data manager .Although the Name string seems absolutely fine in the Data Manager.In short -value in MDM Data Manager for field name was Õ û  Û and output from API was O??u??U??

To my rescue came this class which is worth exploring when you have a situation like above

Class SetUnicodeNormalizationCommand

After you establish your connection to the server through API and Authenticate User Session ,you need to work with this class.

Connection to server would return an object of type ConnectionPool (call it connection)and UserSession authentication would return a string (call it session).Now write this piece of code

SetUnicodeNormalizationCommand cmd = new SetUnicodeNormalizationCommand(connection);

cmd.setSession(session);

cmd.setNormalizationType(SetUnicodeNormalizationCommand.NORMALIZATION_COMPOSED);

cmd.execute();

This class will keep the special characters retrieval intact.

How do you implement a MDM Connection Help Class?

  • In the exmaple Master Data Data Read class we used another class, ZCL_MDM_CONN_POOL_ROOT, to establish the connection to MDM.  This is just a reusable utility class that caches the API connection and contains logic to map the SAP logon langauge to the MDM Language.
  • The complete source code of this class can be downloaded here.
  • Class Properties:
  • Class Private Types:
  • Class Attributes:
  • Class Methods:
  • GET_MDM_CONNECTION
    METHOD get_mdm_connection.
    *@78\QImporting@ LANGUAGE TYPE SYLANGU DEFAULT SY-LANGU
    *@78\QImporting@ UNAME TYPE SYUNAME DEFAULT SY-UNAME
    *@78\QImporting@ REPOSITORY TYPE MDM_LOG_OBJECT_NAME
    *@78\QImporting@ USE_CONNECTION_POOL TYPE BOOLEAN DEFAULT ABAP_TRUE
    *@7B\QReturning@ VALUE( API ) TYPE REF TO CL_MDM_GENERIC_API
    *@03\QException@ CX_MDM_MAIN_EXCEPTION

    IF use_connection_pool = abap_true.
    DATA wa_api LIKE LINE OF api_cache.
    READ TABLE api_cache INTO wa_api
    WITH KEY language = language
    uname = uname
    repository = repository.
    IF sy-subrc = 0.
    ****Cached Connection Record is found, make sure the API reference is bound
    IF wa_api-api IS BOUND.
    api = wa_api-api.
    GET TIME STAMP FIELD wa_api-last_access.
    MODIFY TABLE api_cache FROM wa_api.
    ELSE.
    ****Not bound - Delete the Connection Record and Create a New Instance
    DELETE api_cache WHERE language = language
    AND uname = uname
    AND repository = repository.
    api = zcl_mdm_conn_pool_root=>create_mdm_connection(
    language = language
    uname = uname
    repository = repository
    use_connection_pool = use_connection_pool ).
    ENDIF.
    ELSE.
    ****No Cached Record - Create a New Instance
    api = zcl_mdm_conn_pool_root=>create_mdm_connection(
    language = language
    uname = uname
    repository = repository
    use_connection_pool = use_connection_pool ).
    ENDIF.
    ELSE.
    ****By Pass the Connection Pool and create a one-off Instance
    api = zcl_mdm_conn_pool_root=>create_mdm_connection(
    language = language
    uname = uname
    repository = repository
    use_connection_pool = use_connection_pool ).
    ENDIF.

    ENDMETHOD.



  • CREATE_MDM_CONNECTION
    METHOD create_mdm_connection.
    *@78\QImporting@ LANGUAGE TYPE SYLANGU DEFAULT SY-LANGU
    *@78\QImporting@ UNAME TYPE SYUNAME DEFAULT SY-UNAME
    *@78\QImporting@ REPOSITORY TYPE MDM_LOG_OBJECT_NAME
    *@78\QImporting@ USE_CONNECTION_POOL TYPE BOOLEAN DEFAULT ABAP_TRUE
    *@7B\QReturning@ VALUE( API ) TYPE REF TO CL_MDM_GENERIC_API
    *@03\QException@ CX_MDM_MAIN_EXCEPTION

    DATA mdm_language TYPE mdm_cdt_language_code.
    mdm_language = zcl_mdm_conn_pool_root=>expand_mdm_language( language ).

    **** Instantiate the API with our repository key from the dialog
    CREATE OBJECT api
    EXPORTING
    iv_log_object_name = repository.
    ****Connect to the Repository
    api->mo_accessor->connect( mdm_language ).

    IF use_connection_pool = abap_true.
    DATA wa_api LIKE LINE OF api_cache.
    wa_api-api = api.
    wa_api-language = language.
    wa_api-uname = uname.
    wa_api-repository = repository.
    GET TIME STAMP FIELD wa_api-last_access.
    INSERT wa_api INTO TABLE api_cache.
    ENDIF.

    ENDMETHOD.



  • EXPAND_MDM_LANGUAGE
    METHOD expand_mdm_language.
    *@78\QImporting@ LANGUAGE TYPE SYLANGU DEFAULT SY-LANGU Language Key of Current Text Environment
    *@7B\QReturning@ VALUE( MDM_LANGUAGE ) TYPE MDM_CDT_LANGUAGE_CODE MDM: CDT language code

    CASE language.
    WHEN c_english.
    mdm_language-language = 'eng'.
    mdm_language-country = 'US'.
    mdm_language-region = 'USA'.
    when c_german.
    mdm_language-language = 'ger'.
    mdm_language-country = 'DE'.
    * mdm_language-region = 'USA'.
    WHEN OTHERS.
    ****Use the repository Default
    CLEAR mdm_language.
    ENDCASE.

    ENDMETHOD.


How do you implement the processing for Master Data Read Class Parameters?

  • In the example Master Data Read Class that we have been looking at, the processing is generic.  In other words there is no statement in the application coding that specifies the MDM Repository, Table or Field name.  The values are supplied via parameters so that this same class can be used for more than one Master Data Characteristic.
  • You can see the area where you can supply these parameters in the following screen shot. It is the field labeled Master Data Read Class Parameters:
  • Although this is a single field, it can hold more than one value.  This is done by associating a data dictionary structure with the parameter inside the coding o the Master Data Read Class.  For the purposes of MDM Integration, you probably want a structure something like the one used this example implementation:
  • This way when you click on the pencil icon next the parameter field, a dialog pops up with the individual field selections as defined by your structure.  This even supports value input help for the individual fields.
  • So, how can this functionality be built into the Master Data Read Class?  It requires the implementation of another interface in your class - IF_RSMD_RS_GENERIC.  The sample Master Data Read Class, which can be downloaded here, contains an implementation of this interface for the purposes of processing the MDM Repository, Table and Field as parameters.
  • In the Method GET_STRUCTURE_NAME, you must specify the name of the data dictionary sturcture you are going to use:
    method if_rsmd_rs_generic~get_structure_name.
    e_struct_name = 'ZRSMD_RS_S_MDM'.
    endmethod.



  • But the most important processing are the GET and SET Methods. This is where you must supply the logic to map the data from the single parameter string into the individual fiels of your structure and vise versa:
    method if_rsmd_rs_generic~get_parameter.
    field-symbols: <l_s_struc> type zrsmd_rs_s_mdm.
    assign e_r_struc->* to <l_s_struc>.
    <l_s_struc> = o_s_gendomain.
    endmethod.

    method if_rsmd_rs_generic~set_parameter.
    field-symbols: <l_s_struc> type zrsmd_rs_s_mdm.
    assign i_r_struc->* to <l_s_struc>.
    o_s_gendomain = <l_s_struc>.
    endmethod.

    method if_rsmd_rs_generic~get_parameterstring.
    data: l_parameterstring type rsmdrclpa.

    *===Create the paramater string from the generic table structure===
    l_parameterstring+0(32) = o_s_gendomain-object_name.
    l_parameterstring+32(34) = o_s_gendomain-table .
    l_parameterstring+66(34) = o_s_gendomain-query_field.

    *===Export the parameter string====
    e_parameterstring = l_parameterstring.
    endmethod.

    method if_rsmd_rs_generic~set_parameterstring.
    data: l_parameterstring type rsmdrclpa.

    l_parameterstring = i_parameterstring.
    *===Create the structure from the parameterstring===
    o_s_gendomain-object_name = l_parameterstring+0(32).
    o_s_gendomain-table = l_parameterstring+32(34).
    o_s_gendomain-query_field = l_parameterstring+66(34).
    endmethod.


How do you implement the Master Data Read Class?

  • Master Data Read Classes have one basic requirement - They must implement the IF_RSMD_RS_ACCESS interface.
  • There are several examples of how implement a Master Data Read Class provided by SAP - like CL_RSMD_RS_GENERIC_DOMAIN and CL_RSMD_RS_GENERIC_TABLE.  For creating your own custom Master Data Read Class, it probably makes sense to start by copying from one these existing classes and only adjusting for your specific processing.
  • The complete source code (in SAPlink format) for an example implementation of a Master Data Read Class that uses MDM and the MDM ABAP APIs can be downloaded from here.
  • Of all the methods in the sample class the most important from the standpoint of the MDM integration is the GET_TEXT method. The example implementation supports the retrieval of STRING or INTEGER based supporting values for a given key from MDM:
METHOD if_rsmd_rs_access~get_text.

DATA: object_name TYPE mdm_log_object_name,
table TYPE mdm_table_code,
query_field TYPE mdm_field_code,
l_s_chavlinfo TYPE rsdm_s_chavlinfo,
l_not_assigned TYPE rs_txtlg,
l_initial_val TYPE rsd_chavl.

object_name = o_s_gendomain-object_name.
table = o_s_gendomain-table.
query_field = o_s_gendomain-query_field.


DATA lt_result_set_definition TYPE mdm_field_list_table.
DATA ls_result_set_definition LIKE LINE OF lt_result_set_definition.
DATA lt_result_set TYPE mdm_result_set_table.
DATA ls_result_set LIKE LINE OF lt_result_set.
DATA lt_result_set2 TYPE mdm_result_set_table.
DATA ls_result_set2 LIKE LINE OF lt_result_set2.
DATA ls_remote_key_filter TYPE mdm_client_system_key_query.
DATA api TYPE REF TO cl_mdm_generic_api.
DATA language TYPE mdm_cdt_language_code.
DATA keys TYPE mdm_keys.
DATA exception TYPE REF TO cx_mdm_main_exception.
FIELD-SYMBOLS <field_value> TYPE ANY.
FIELD-SYMBOLS: <wa_field> TYPE mdm_cdt_text,
<wa_string> TYPE string,
<wa_integer> TYPE mdm_gdt_integervalue,
<wa_taxonomy> TYPE mdm_taxonomy_entry,
<wa_int> TYPE mdm_gdt_integervalue.
TYPE-POOLS: mdmif.

TRY.

DATA wa_cache LIKE LINE OF me->data_cache.
READ TABLE data_cache INTO wa_cache
WITH KEY object_name = object_name
table = table
query_field = query_field.
IF sy-subrc = 0.
keys = wa_cache-keys.
lt_result_set = wa_cache-lt_result_set.
ELSE.

api = zcl_mdm_conn_pool_root=>get_mdm_connection( repository = object_name ).

DATA: result_set TYPE mdm_search_result_table.
CALL METHOD api->mo_core_service->query
EXPORTING
iv_object_type_code = table
* iv_hits_max = 1
IMPORTING
et_result_set = result_set.

****The results of a query only return the record keys - no details
****We then have to use a call to the method RETRIEVE to read
****the record details.
DATA: result TYPE mdm_search_result.
READ TABLE result_set INDEX 1 INTO result.
IF sy-subrc = 0.
keys = result-record_ids.
ENDIF.

CHECK keys IS NOT INITIAL.
****We only need the output field we are interested read from MDM
****By using the result_set_definition parameter, we can control this
****and only retrieve that single column
ls_result_set_definition-field_name = query_field.
APPEND ls_result_set_definition TO lt_result_set_definition.
CALL METHOD api->mo_core_service->retrieve
EXPORTING
iv_object_type_code = table
it_result_set_definition = lt_result_set_definition
it_keys = keys
IMPORTING
et_result_set = lt_result_set.

CLEAR wa_cache.
wa_cache-object_name = object_name.
wa_cache-table = table.
wa_cache-query_field = query_field.
wa_cache-keys = keys.
wa_cache-lt_result_set = lt_result_set.
APPEND wa_cache TO data_cache.
ENDIF.

*===Get the Initial Value Text===
CALL METHOD _textpool_read
EXPORTING
i_repid = 'SAPLRSDM'
i_key = '001'
IMPORTING
e_text = l_not_assigned.

FIELD-SYMBOLS: <wa_result> LIKE LINE OF lt_result_set.
FIELD-SYMBOLS: <wa_pair> TYPE mdm_name_value_pair,
<wa_key> LIKE LINE OF keys.

*===Append the text values in c_t_chavlinfo===
DATA: tabix TYPE sy-tabix.
DATA l_integer TYPE mdm_gdt_integervalue.
FIELD-SYMBOLS: <l_s_chavlinfo> TYPE rsdm_s_chavlinfo.
LOOP AT c_t_chavlinfo ASSIGNING <l_s_chavlinfo>
WHERE i_read_mode = rsdm_c_read_mode-text.
CLEAR <l_s_chavlinfo>-c_rc.
IF <l_s_chavlinfo>-c_chavl IS INITIAL
OR <l_s_chavlinfo>-c_chavl EQ rsd_c_initial
OR <l_s_chavlinfo>-c_chavl < 1.
<l_s_chavlinfo>-e_chatexts-txtsh = l_not_assigned.
<l_s_chavlinfo>-e_chatexts-txtmd = l_not_assigned.
<l_s_chavlinfo>-e_chatexts-txtlg = l_not_assigned.
ELSE.
l_integer = <l_s_chavlinfo>-c_chavl.
READ TABLE keys ASSIGNING <wa_key> FROM l_integer.
tabix = sy-tabix.
READ TABLE lt_result_set ASSIGNING <wa_result> INDEX tabix.
IF sy-subrc = 0.
READ TABLE <wa_result>-name_value_pairs ASSIGNING <wa_pair>
WITH KEY code = query_field.
IF sy-subrc = 0.
****The data for the column could be one of various data types
****The value itself is returned as TYPE REF TO DATA and must
****be cast into a more specific data type before it can be processed.
CASE <wa_pair>-type.
WHEN 'STRING'.
ASSIGN <wa_pair>-value->* TO <wa_string>.
WRITE <wa_key> TO l_s_chavlinfo-c_chavl LEFT-JUSTIFIED.
<l_s_chavlinfo>-e_chatexts-txtsh = <wa_string>.
<l_s_chavlinfo>-e_chatexts-txtmd = <wa_string>.
<l_s_chavlinfo>-e_chatexts-txtlg = <wa_string>.
WHEN 'INTEGER'.
ASSIGN <wa_pair>-value->* TO <wa_integer>.
WRITE <wa_key> TO l_s_chavlinfo-c_chavl LEFT-JUSTIFIED.
<l_s_chavlinfo>-e_chatexts-txtsh = <wa_integer>.
<l_s_chavlinfo>-e_chatexts-txtmd = <wa_integer>.
<l_s_chavlinfo>-e_chatexts-txtlg = <wa_integer>.
ENDCASE.
ENDIF.
ENDIF.
ENDIF.
ENDLOOP.
ENDTRY.
ENDMETHOD.

SAP Developer Network Latest Updates