Saturday, November 27, 2010

Creating Customized Search Strategy in IBM MDM

Introduction:
The Infosphere MDM Server provides us with a number of transactions to retrive the information stored by it in order to come up with high value customer data for analytic's ,reports ,to device new marketing strategies. The OOTB solutions can be customized so as to suit the clients requirements across various domains/industries.

Business Scenario:
Consider a scenario  of  the customer care center where thousands of customer calls up for various services ranging from the registering comapliants,to know about the various offers & services ,for a critical data change like address phone number. The call center agent will do a search based on the information provided by the customer to  validate his identity by asking a set of questions like dob, lastname,phone number etc.
The customers generally don’t like to wait on the line for long time and hence the performance of the system / response time is a major criteria.

Implementation  Strategies:
1)End to End Customization
2)Extending the Search rule & utilizing the search framework.
The first approach is already discussed in one of my previous blogs.

There are a few OOTB transactions available for ready use in the MDM server. For e.g.: if your search criteria is  related to person details like given name one,lastname etc you can think of using the search Person .If the search criteria is from the contract region we can use the searchContract.Also if the criteria is a mix of person & contract details you can use the searchFSParty transaction. The OOTB solutions make use of the SearchParty external rule.

In the case of my client they provide a unique card called privilege card for all it customers. This card number is accommodated in the data model as an extension on the CONTRACT table.None of the OOTB solutions support for searching based on an  extended field I have to write sqls for search based on this extended field.



In general the approach you can follow is
1)Common Search Exclusion
When ever a search request comes in check whether the criteria can result in a potentially huge result set.
For eg: A search based on common lastnames like Philip,Thomas etc can result in a large result set.
You can leverage the external validations to configure the Disallowed Search list to prevent a search on these common attributes.This feature prevent poor quality searches from executed against the MDM database
2)Configuring maxResult
The next thing we can focus on is configuring the maximum results that needs to be returned.It is available as a simple configuration in the CONFIGELEMENT table .
/IBM/Party/Search/maxResults
The default value is 100.The normal approach followed is use the value in CONFIGELEMENT as the default one ,but if the value for maxresult(Available in the request object) is less than what is configured in the table we are happy to return the what is provided in the request object.
3)External Rule
The first 2 steps can be done from inside a custom bp & the search strategy can implemented inside a Rule class.A modification to the search rule is needed only when client specific customizations are needed.
For eg: Search based on an extended field.
So what should be done in the rule is check if the request has got any extended attributes.If yes you have to invoke client defined sqls(which can be pre written and stored in tables or stored in some sql helper classes).
else invoke the OOTB services.
4)Ranking and Sorting.
5)Return the result.

These are the basic steps in creating a customized search strategy.




Wednesday, July 28, 2010

Implementing Pagination in IBM MDM

Before you start implementing the pagination feature for your search functionality I recommend you to explore the pagination facility for one of the existing search service.
For eg: searchFSParty





Note that inside the <dwlcontrol>  I had placed a few things extra.
   <pagestartindex>1</pagestartindex>
   <pageendindex>3</pageendindex>
   <returnavailableresultcount>true </returnavailableresultcount>


Example 1
If the pageStartIndex is 1, the pageEndIndex is 10, and the total result count is 16, then 10 records will be returned in the first subset, and 6 records will be returned in the second subset.

Example 2
 If the pageStartIndex is 1, the pageEndIndex is 10, and the total result count is 8, then the pageEndIndex is considered to be equal to the total count, and 8 records will be returned in the set.

Now we are ready to implement the pagination in our custom search transactions.
(Please read about how to create a custom search in my previous post)


1. The user sends a request XML for searchCustomer(My custom search transaction) transactions including  the pagination parameters. 
Pagiantion Pramaters:

    <pagestartindex>1 </pagestartindex>
   <pageendindex>3</pageendindex> 
   <returnavailableresultcount>true </returnavailableresultcount>
(Will help you return the total number of records available on executing the query for your search.)

2. Inside the controller class for our searchCustomer/handlesearchCustomer we have to add response BObj class name in the DWLControl

 You will be having a method generated in you controller like the one below.
 public DWLResponse searchCustomer(xxxRequestBObj theBObj) throws DWLBaseException
 Add the following:
 Vector reponseBobsForTxn=new Vector(); reponseBobsForTxn.add("com.mycompany.xxxResponseBObj");
 theBObj.getControl().setResponseBObjsForTxn(reponseBobsForTxn);

Now come back to your component class:

3.Add the following just above your List list = bObjQuery.getResults();
boolean considerForPagination = PaginationUtils.considerForPagintion(xxxResponseBObj.class.getName(), theBObj.getControl());
theBObj.getControl().setConsiderForPagintionFlag(considerForPagination);
System.out.println("Start Index--"+theBObj.getControl().getPageStartIndex());
System.out.println("End Index---"+theBObj.getControl().getPageEndIndex());

Now you are done with the pagination implementation for you custom search.
To add to this if you want to restrict the size of the result set returned by a search transaction. Add the following line of code in your component class after you got the bObjQuery.
bObjQuery.setMaxResults(int);

What I had done to configure the max result count is add a 'maxresults' tag to my custom request object so that the user can configure the max results returned.





Thursday, June 24, 2010

Customizing MDM Retrieval Service

There are two approaches for customizing the MDM retrieval service.


·         Approach 1:----End to end customization.
                              Here we should have complete control over SQL and how we build object structure.
          Approach 2:----Extension of the inbuilt ones.
                              Extending MDM Search Framework.

In this post I wish to emphasize on the first approach.

Retrival service with complete control over SQL:
First of all create a new module project. & follow the below steps.


1. Create a new MDM entity(Right click ->New MDM Entity)   (request object)  and populate with search criteria

2. Create a new MDM entity (response object) and populate with attributes you wish to return



3. Create a new MDM Tx,  View type, multiple records returned  set the request and response(The entities we created in Step 1 & 2)





We are trying to make use of MDM Entity addition to generate the request & response objects,but we will never
execute the scripts for entity addition to db.We just need the project skelton.For implementing the retrival service
we created a new MDM Txn with the request & response objects as the entity we created earlier.

Now go and generate the code.


Within the generated code there are a few places that you need  to modify:
In the component class, populate the handleXXX( BObj ) method where XXX is the name of your transaction.


CustomSearchFrameworkComponent.java:

public DWLResponse handleSearchByClubCardNumber(SearchRequestBObj theBObj) throws Exception {
   
        DWLStatus status = new DWLStatus();
        status.setStatus(DWLStatus.SUCCESS);
        DWLResponse response = createDWLResponse();     
        BObjQuery bObjQuery = null;

        bObjQuery = getBObjQueryFactory().createSearchRequestBObjQuery(SearchRequestBObjQuery.SEARCH_REQUEST_QUERY,
                theBObj.getControl());
       
        bObjQuery.setParameter("BObj", theBObj);          
        List list = bObjQuery.getResults();

        Vector vector = new Vector();
        for (Iterator it = list.iterator(); it.hasNext();) {
           SearchResponseBObj o = (SearchResponseBObj) it.next();

            vector.add(o);

            if (o != null) {
                if (o.getStatus()==null) {
                    o.setStatus(status);
                }
                response.addStatus(o.getStatus());
            } else {
                response.addStatus(o.getStatus());
            }
        }

        response.setData(vector);

        return response;
       

    }

In the BObjQuery class for the request object populate the provideSqlStatement() to return your custom sql, and change the
provideResultSetProcessor() method.

provideSQLStatement() is not available by default in the BObjQuery class.
Right click inside the class ,Perform an Override /Implement ->Select  provideSQLStatement()
or simply copy paste the code below.



@Override
    protected String provideSQLStatement() throws BObjQueryException {
        SQLParam sqlParam = (SQLParam) this.namedParams.get("BObj");
        SearchRequestBObj csRequObj=(SearchRequestBObj)sqlParam.getValue();
        System.err.println("Search Attribute---"+csRequObj.getClubCardNumber()+"####");
        // TODO Create the SQL HERE !!!!!
        String clubCard="'"+csRequObj.getClubCardNumber().trim()+"'";
       
        //I am simply getting  LINE_OF_BUSINESS & setting it to person name.(doesn't sounds logical forgive me it
        //is just an example.
        String sql= "select LINE_OF_BUSINESS from CONTRACT where XClub_Card_Id ="+clubCard;
       
       
        return sql;
    }

   
   
Change the provideResultSetProcessor() method. 

By default in generated code the reult processor returned is  SearchRequestResultSetProcessor ,but I had written my code in
SearchResponseResultSetProcessor().So changing it.
   
 /**
     *
     *
     *
     * Provides the result set processor that is used to populate the business
     * object.
     *
     * @return
     * An instance of SearchRequestResultSetProcessor.
     *
     * @see com.dwl.bobj.query.AbstractBObjQuery#provideResultSetProcessor()
     * @see com.mycompany.mdm.search.component.SearchRequestResultSetProcessor
     *
     * @generated NOT
     */
    protected IGenericResultSetProcessor provideResultSetProcessor()
            throws BObjQueryException {

        //return new SearchRequestResultSetProcessor();
        return new  SearchResponseResultSetProcessor();
    }   
   
Both the methods are invoked when     List list = bObjQuery.getResults(); is executed from the handleSearchByClubCardNumber() in
CustomSearchFrameworkComponent class.

In the above code we cahnged the reult set processor to "return new  SearchResponseResultSetProcessor()",but we are yet to write code in SearchResponseResultSetProcessor


In  SearchResponseResultSetProcessor class for the response object, populate the getObjectFromResultSet() method:


  /**
     *
     *
     *
     * Creates business objects from the supplied result set.
     *
     * @generated NOT
     */
    public Vector getObjectFromResultSet(ResultSet rs) throws Exception {
        Vector boVector = new Vector();
       
        // loop through the result set and get the column data
        while ( rs.next() ) {
            boVector.add( getBObjFromRS( rs ) );
        }
       
        return boVector;
    }

    /**
     *
     *
     *
     * Creates one business object from the supplied result set.
     *
     * @generated NOT
     */
    private SearchResponseBObj getBObjFromRS( ResultSet rs ) {
        SearchResponseBObj bobj = new SearchResponseBObj();
       
        try {
            // *** These MUST match the parameters requested in the SQL.
            /*bobj.setName( rs.getString(1) );
            bobj.setDOB( rs.getString(2) );
            bobj.setAddressLine1( rs.getString(3) );
            bobj.setAddressLine2( rs.getString(4) );
            bobj.setCity( rs.getString(5) );
            bobj.setPostCode( rs.getString(6) );
             */
            bobj.setPersonName(rs.getString(1));
            //bobj.setLineofBusiness(rs.getString(2));
           
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
       
        return bobj;
    }

Now  lets move on to our dtd,xsd,properties file & db changes.


It is a must that we put the  SearchRequestBObj?, SearchResponseBObj? in TCRMExtension.
Please see the liks to dtds & xsd at the bottom of the post.

Now you are done with merging.

DB Insert Statements:Only the METADATA file  you need to execute & only the following statements you need to execute.

-- Notes
-- MDM TODO statements are placed in the generated SQL file when user changes are required.
-- 1. Edit the following SQL files following any instructions given by MDM TODO statements.
-- 2. Connect to the database.
-- 3. Run each SQL file as shown below and in the same order.
--             db2 -tvf CustomSearchFramework_SETUP_DB2.sql
--             db2 -v -td@ -f CustomSearchFramework_TRIGGERS_DB2.sql
--             db2 -tvf CustomSearchFramework_CONSTRAINTS_DB2.sql
--             db2 -tvf CustomSearchFramework_MetaData_DB2.sql


----------------------------------------------
-- Component type
----------------------------------------------

INSERT INTO DB2ADMIN.COMPONENTTYPE (COMPONENT_TYPE_ID, DWL_PROD_TP_CD, COMPON_TYPE_VALUE, COMPON_LONG_DESC, LAST_UPDATE_DT)
   VALUES ( 1000032, 1, 'CustomSearchFrameworkFinderImpl', null, CURRENT TIMESTAMP);
INSERT INTO DB2ADMIN.COMPONENTTYPE (COMPONENT_TYPE_ID, DWL_PROD_TP_CD, COMPON_TYPE_VALUE, COMPON_LONG_DESC, LAST_UPDATE_DT)
   VALUES ( 1000030, 1, 'SearchRequestBObj', null, CURRENT TIMESTAMP);
INSERT INTO DB2ADMIN.COMPONENTTYPE (COMPONENT_TYPE_ID, DWL_PROD_TP_CD, COMPON_TYPE_VALUE, COMPON_LONG_DESC, LAST_UPDATE_DT)
   VALUES ( 1000034, 1, 'CustomSearchFrameworkComponent', null, CURRENT TIMESTAMP);
INSERT INTO DB2ADMIN.COMPONENTTYPE (COMPONENT_TYPE_ID, DWL_PROD_TP_CD, COMPON_TYPE_VALUE, COMPON_LONG_DESC, LAST_UPDATE_DT)
   VALUES ( 1000043, 1, 'SearchResponseBObj', null, CURRENT TIMESTAMP);

----------------------------------------------
-- Add SearchRequest object to V_GROUP table
----------------------------------------------

INSERT INTO DB2ADMIN.V_GROUP (GROUP_NAME, APPLICATION, OBJECT_NAME, LAST_UPDATE_DT, SORTBY)
  VALUES ('SearchRequestBObj', 'TCRM', 'com.mycompany.mdm.search.component.SearchRequestBObj', CURRENT TIMESTAMP, 'LAST_UPDATE_DT');


----------------------------------------------
-- Add SearchResponse object to V_GROUP table
----------------------------------------------

INSERT INTO DB2ADMIN.V_GROUP (GROUP_NAME, APPLICATION, OBJECT_NAME, LAST_UPDATE_DT, SORTBY)
  VALUES ('SearchResponseBObj', 'TCRM', 'com.mycompany.mdm.search.component.SearchResponseBObj', CURRENT TIMESTAMP, 'LAST_UPDATE_DT');


----------------------------------------------
-- Transactions
----------------------------------------------

INSERT INTO DB2ADMIN.CDBUSINESSTXTP (BUSINESS_TX_TP_CD, NAME, DESCRIPTION, EXPIRY_DT, LAST_UPDATE_DT, TX_LOG_IND, TX_OBJECT_TP, DEPRECATED_SINCE, DWL_PROD_TP_CD)
   VALUES (1000006, 'addSearchRequest',  null, null, CURRENT TIMESTAMP, 'Y', 'P', null, 1);
  
INSERT INTO DB2ADMIN.BUSINESSTXREQRESP (BUSTX_REQRESP_ID, BUSINESS_TX_TP_CD, APPLICATION, GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, LAST_UPDATE_USER, LAST_UPDATE_DT, COLLECTION_IND)
values (1000108, 1000006, 'TCRM', 'SearchRequestBObj', 'I', null, null, 1, 'cusadmin', CURRENT TIMESTAMP, null);

INSERT INTO DB2ADMIN.BUSINESSTXREQRESP (BUSTX_REQRESP_ID, BUSINESS_TX_TP_CD, APPLICATION, GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, LAST_UPDATE_USER, LAST_UPDATE_DT, COLLECTION_IND)
values (1000109, 1000006, 'TCRM', 'SearchRequestBObj', 'O', null, null, null, 'cusadmin', CURRENT TIMESTAMP, 'Y');
       
INSERT INTO DB2ADMIN.CDBUSINESSTXTP (BUSINESS_TX_TP_CD, NAME, DESCRIPTION, EXPIRY_DT, LAST_UPDATE_DT, TX_LOG_IND, TX_OBJECT_TP, DEPRECATED_SINCE, DWL_PROD_TP_CD)
   VALUES (1000009, 'updateSearchRequest',  null, null, CURRENT TIMESTAMP, 'Y', 'P', null, 1);
  
INSERT INTO DB2ADMIN.BUSINESSTXREQRESP (BUSTX_REQRESP_ID, BUSINESS_TX_TP_CD, APPLICATION, GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, LAST_UPDATE_USER, LAST_UPDATE_DT, COLLECTION_IND)
values (1000110, 1000009, 'TCRM', 'SearchRequestBObj', 'I', null, null, 1, 'cusadmin', CURRENT TIMESTAMP, null);

INSERT INTO DB2ADMIN.BUSINESSTXREQRESP (BUSTX_REQRESP_ID, BUSINESS_TX_TP_CD, APPLICATION, GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, LAST_UPDATE_USER, LAST_UPDATE_DT, COLLECTION_IND)
values (1000111, 1000009, 'TCRM', 'SearchRequestBObj', 'O', null, null, null, 'cusadmin', CURRENT TIMESTAMP, 'Y');
       
INSERT INTO DB2ADMIN.CDBUSINESSTXTP (BUSINESS_TX_TP_CD, NAME, DESCRIPTION, EXPIRY_DT, LAST_UPDATE_DT, TX_LOG_IND, TX_OBJECT_TP, DEPRECATED_SINCE, DWL_PROD_TP_CD)
   VALUES (1000011, 'getSearchRequest', null, null, CURRENT TIMESTAMP, 'Y', 'I', null, 1);

INSERT INTO DB2ADMIN.BUSINESSTXREQRESP (BUSTX_REQRESP_ID, BUSINESS_TX_TP_CD, APPLICATION, GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, LAST_UPDATE_USER, LAST_UPDATE_DT, COLLECTION_IND)
values (1000112, 1000011, null, null, 'I', 1, 'pkId', 1, 'cusadmin', CURRENT TIMESTAMP, null);

INSERT INTO DB2ADMIN.BUSINESSTXREQRESP (BUSTX_REQRESP_ID, BUSINESS_TX_TP_CD, APPLICATION, GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, LAST_UPDATE_USER, LAST_UPDATE_DT, COLLECTION_IND)
values (1000113, 1000011, null, null, 'I', 5, 'aDWLControl', 2, 'cusadmin', CURRENT TIMESTAMP, null);

INSERT INTO DB2ADMIN.BUSINESSTXREQRESP (BUSTX_REQRESP_ID, BUSINESS_TX_TP_CD, APPLICATION, GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, LAST_UPDATE_USER, LAST_UPDATE_DT, COLLECTION_IND)
values (1000114, 1000011, 'TCRM', 'SearchRequestBObj', 'O', null, null, null, 'cusadmin', CURRENT TIMESTAMP, 'Y');

INSERT INTO DB2ADMIN.CDBUSINESSTXTP (BUSINESS_TX_TP_CD, NAME, DESCRIPTION, EXPIRY_DT, LAST_UPDATE_DT, TX_LOG_IND, TX_OBJECT_TP, DEPRECATED_SINCE, DWL_PROD_TP_CD)
   VALUES (1000019, 'addSearchResponse',  null, null, CURRENT TIMESTAMP, 'Y', 'P', null, 1);
  
INSERT INTO DB2ADMIN.BUSINESSTXREQRESP (BUSTX_REQRESP_ID, BUSINESS_TX_TP_CD, APPLICATION, GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, LAST_UPDATE_USER, LAST_UPDATE_DT, COLLECTION_IND)
values (1000115, 1000019, 'TCRM', 'SearchResponseBObj', 'I', null, null, 1, 'cusadmin', CURRENT TIMESTAMP, null);

INSERT INTO DB2ADMIN.BUSINESSTXREQRESP (BUSTX_REQRESP_ID, BUSINESS_TX_TP_CD, APPLICATION, GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, LAST_UPDATE_USER, LAST_UPDATE_DT, COLLECTION_IND)
values (1000116, 1000019, 'TCRM', 'SearchResponseBObj', 'O', null, null, null, 'cusadmin', CURRENT TIMESTAMP, 'Y');
       
INSERT INTO DB2ADMIN.CDBUSINESSTXTP (BUSINESS_TX_TP_CD, NAME, DESCRIPTION, EXPIRY_DT, LAST_UPDATE_DT, TX_LOG_IND, TX_OBJECT_TP, DEPRECATED_SINCE, DWL_PROD_TP_CD)
   VALUES (1000022, 'updateSearchResponse',  null, null, CURRENT TIMESTAMP, 'Y', 'P', null, 1);
  
INSERT INTO DB2ADMIN.BUSINESSTXREQRESP (BUSTX_REQRESP_ID, BUSINESS_TX_TP_CD, APPLICATION, GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, LAST_UPDATE_USER, LAST_UPDATE_DT, COLLECTION_IND)
values (1000117, 1000022, 'TCRM', 'SearchResponseBObj', 'I', null, null, 1, 'cusadmin', CURRENT TIMESTAMP, null);

INSERT INTO DB2ADMIN.BUSINESSTXREQRESP (BUSTX_REQRESP_ID, BUSINESS_TX_TP_CD, APPLICATION, GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, LAST_UPDATE_USER, LAST_UPDATE_DT, COLLECTION_IND)
values (1000118, 1000022, 'TCRM', 'SearchResponseBObj', 'O', null, null, null, 'cusadmin', CURRENT TIMESTAMP, 'Y');
       
INSERT INTO DB2ADMIN.CDBUSINESSTXTP (BUSINESS_TX_TP_CD, NAME, DESCRIPTION, EXPIRY_DT, LAST_UPDATE_DT, TX_LOG_IND, TX_OBJECT_TP, DEPRECATED_SINCE, DWL_PROD_TP_CD)
   VALUES (1000024, 'getSearchResponse', null, null, CURRENT TIMESTAMP, 'Y', 'I', null, 1);

INSERT INTO DB2ADMIN.BUSINESSTXREQRESP (BUSTX_REQRESP_ID, BUSINESS_TX_TP_CD, APPLICATION, GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, LAST_UPDATE_USER, LAST_UPDATE_DT, COLLECTION_IND)
values (1000119, 1000024, null, null, 'I', 1, 'pkId', 1, 'cusadmin', CURRENT TIMESTAMP, null);

INSERT INTO DB2ADMIN.BUSINESSTXREQRESP (BUSTX_REQRESP_ID, BUSINESS_TX_TP_CD, APPLICATION, GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, LAST_UPDATE_USER, LAST_UPDATE_DT, COLLECTION_IND)
values (1000120, 1000024, null, null, 'I', 5, 'aDWLControl', 2, 'cusadmin', CURRENT TIMESTAMP, null);

INSERT INTO DB2ADMIN.BUSINESSTXREQRESP (BUSTX_REQRESP_ID, BUSINESS_TX_TP_CD, APPLICATION, GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, LAST_UPDATE_USER, LAST_UPDATE_DT, COLLECTION_IND)
values (1000121, 1000024, 'TCRM', 'SearchResponseBObj', 'O', null, null, null, 'cusadmin', CURRENT TIMESTAMP, 'Y');

INSERT INTO DB2ADMIN.CDBUSINESSTXTP (BUSINESS_TX_TP_CD, NAME, DESCRIPTION, EXPIRY_DT, LAST_UPDATE_DT, TX_LOG_IND, TX_OBJECT_TP, DEPRECATED_SINCE, DWL_PROD_TP_CD)
   VALUES (1000028, 'searchByClubCardNumber',  null, null, CURRENT TIMESTAMP, 'Y', 'P', null, 1);
  
INSERT INTO DB2ADMIN.BUSINESSTXREQRESP (BUSTX_REQRESP_ID, BUSINESS_TX_TP_CD, APPLICATION, GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, LAST_UPDATE_USER, LAST_UPDATE_DT, COLLECTION_IND)
values (1000122, 1000028, 'TCRM', 'SearchRequestBObj', 'I', null, null, 1, 'cusadmin', CURRENT TIMESTAMP, null);

INSERT INTO DB2ADMIN.BUSINESSTXREQRESP (BUSTX_REQRESP_ID, BUSINESS_TX_TP_CD, APPLICATION, GROUP_NAME, REQ_RESP_IND, TX_PARAM_TP_CD, PARAM_NAME, PARAM_ORDER, LAST_UPDATE_USER, LAST_UPDATE_DT, COLLECTION_IND)
values (1000123, 1000028, 'TCRM', 'SearchResponseBObj', 'O', null, null, null, 'cusadmin', CURRENT TIMESTAMP, 'N');
       

For transactions:

In CDBUSINESSTXTP &  BUSINESSTXREQRESP you can insert the statemets for searchByClubCardNumber alone,but I added for
add,update& get also.No specific reasons just for safety.


In tcrm_extension.properties


#-------------Added for CustomSearchFramework

#-----------------------------------------------------------------------
# ADDITION: SearchRequest CONTROLLER METHODS
#
addSearchRequest = com.mycompany.mdm.search.controller.CustomSearchFrameworkTxnBean
updateSearchRequest = com.mycompany.mdm.search.controller.CustomSearchFrameworkTxnBean
getSearchRequest = com.mycompany.mdm.search.controller.CustomSearchFrameworkFinderImpl

#-----------------------------------------------------------------------
# ADDITION: SearchRequestBObj BUSINESS OBJECT
#
SearchRequestBObj = com.mycompany.mdm.search.component

#-----------------------------------------------------------------------
# ADDITION: SearchRequestBObj WEB SERVICES
services.endpoints.message.converter.com.mycompany.mdm.search.component.SearchRequestBObj=com.mycompany.mdm.search.customsearchframework.service.to.convert.SearchRequestBObjConverter
services.endpoints.message.converter.com.mycompany.mdm.search.customsearchframework.service.to.SearchRequest=com.mycompany.mdm.search.customsearchframework.service.to.convert.SearchRequestBObjConverter

#-----------------------------------------------------------------------
# ADDITION: SearchResponse CONTROLLER METHODS
#
addSearchResponse = com.mycompany.mdm.search.controller.CustomSearchFrameworkTxnBean
updateSearchResponse = com.mycompany.mdm.search.controller.CustomSearchFrameworkTxnBean
getSearchResponse = com.mycompany.mdm.search.controller.CustomSearchFrameworkFinderImpl

#-----------------------------------------------------------------------
# ADDITION: SearchResponseBObj BUSINESS OBJECT
#
SearchResponseBObj = com.mycompany.mdm.search.component

#-----------------------------------------------------------------------
# ADDITION: SearchResponseBObj WEB SERVICES
services.endpoints.message.converter.com.mycompany.mdm.search.component.SearchResponseBObj=com.mycompany.mdm.search.customsearchframework.service.to.convert.SearchResponseBObjConverter
services.endpoints.message.converter.com.mycompany.mdm.search.customsearchframework.service.to.SearchResponse=com.mycompany.mdm.search.customsearchframework.service.to.convert.SearchResponseBObjConverter

CustomSearchFramework.BObjQueryFactory=com.mycompany.mdm.search.bobj.query.CustomSearchFrameworkModuleBObjQueryFactoryImpl
customsearchframework_component = com.mycompany.mdm.search.component.CustomSearchFrameworkComponent
   
searchByClubCardNumber = com.mycompany.mdm.search.controller.CustomSearchFrameworkFinderImpl

In DWLCommon_extension.properties

#-------------Added for CustomSearchFramework


###################################################
# Webservices addition
###################################################

Parser.tcrm.CustomSearchFrameworkService=com.mycompany.mdm.search.customsearchframework.service.to.convert.CustomSearchFrameworkServiceRequestParser
Constructor.tcrm.CustomSearchFrameworkService=com.mycompany.mdm.search.customsearchframework.service.to.convert.CustomSearchFrameworkServiceResponseConstructor

Now you are ready!!.


Here is your request xml.

              RequestXML



Response:
             Response of Search





Links to dtd & xsds:


http://docs.google.com/leaf?id=0B3obvedGI1lvZTg3MjVkZmMtZmVhNS00MDU1LWJlNTUtM2VlOTNkOTNkMTRm&sort=name&layout=list&num=50

Thursday, June 10, 2010

IBM MDM Composite Transactions

As per the IBM MDM developers guide there are 2 ways for implementing Composite Transactions.

1)Using custom business proxies.
2)Using composite xml transactions.
Here we will discuss the first approach.
The steps to be followed are in creating a Business Proxy(BP) are

1. Create a  Java project and your BP class extending the DWLTXnBP
2. Override the execute method.
3. Entry in DWLCommon_extension.properties.
4. Register the transaction name in CDBUSINESSTXTP & COMPONENTTYPE table.
5.Given dependency to the BP java project in  MDM.EAR.
6.Associate jars to the build path of the Java project we created.
7.Add reference in Manifest of DWLCommonServiceEJB.
8. Stop,Clean build,publish and run the transaction through XML Tester.

Step 1: Create a  Java project and your BP class extending the DWLTXnBP
Create a Java project Eg:BasicCompositeTransactionProject
My Class I named it like CreateCustomerBP.java

Step 2:Override the execute method.
public Object execute(Object arg0) throws BusinessProxyException{
//Give a Sysout for testing.
}

Step 3:Entry in DWLCommon_extension.properties.
Add the following entry in DWLCommon_extension.properties
BusinessProxy.tcrm.myXXXTranasactionName = com.XXXXX.mdm.MyCustomBP

Eg:
BusinessProxy.tcrm.createCustomerComposite=com.XXXX.mdm.CreateCustomerBP


Step 4:Register the transaction name in CDBUSINESSTXTP table .
insert into DB2ADMIN.CDBUSINESSTXTP (business_tx_tp_cd, name, tx_log_ind, last_update_dt, tx_object_tp)
 values (900201, 'createCustomerComposite', 'Y', current timestamp, 'P');

INSERT INTO DB2ADMIN.COMPONENTTYPE (COMPONENT_TYPE_ID, DWL_PROD_TP_CD, COMPON_TYPE_VALUE, COMPON_LONG_DESC, LAST_UPDATE_DT)
VALUES (900201, 1, 'CreateCustomerBP', 'DWLSampleCreateCustomerBP Composite Transaction Business Proxy', CURRENT TIMESTAMP);

Step 5:Given dependency to the BP java project in  MDM.EAR
Inside MDM project ->META-INF->application.xml ->Module tab ->Project Utility jars->Add BasicCompositeTransactionProject.jar




Step 6.Associate jars to the build path of the Java project we created.

CoreUtilities.jar ManagementCommon.jar CommonUtilities.jar Logging.jar ConfigurationRepository.jar ConfigurationClient.jar DWLCommonServices.jar icu4j.jar BTM.jar Services.jar Base.jar




Step 7.Add reference in Manifest of DWLCommonServiceEJB .
Go to DWLCommonServicesEJB ->MET-INF->Manifest.mf -> Dependencies->Check BasicCompositeTransactionProject.jar


8. Stop,Clean build,publish and run the transaction through XML Tester.
Try Add/Remove the MDM by right clicking the server.

One normal error that we see in the course of  development is

BTM ITxRxException occurred in Request and Response Framework.
<Throwable>com.dwl.base.exception.DWLBaseException: com.mypack.compositetxns.CreateCustomerBP</Throwable>

The main reason is not following the step 7.Add reference in Manifest of DWLCommonServiceEJB properly.

Sample Code:

import com.dwl.base.DWLCommon;
import com.dwl.base.DWLControl;
import com.dwl.base.requestHandler.DWLTransactionPersistent;
import com.dwl.base.requestHandler.DWLTxnBP;
import com.dwl.tcrm.common.TCRMCommon;
import com.dwl.tcrm.common.TCRMResponse;
import com.dwl.tcrm.financial.component.TCRMContractBObj;
import com.dwl.unifi.tx.exception.BusinessProxyException;
import com.XXX.app.tscd.extension.component.XContractBObjExt;





public class CreateCustomerBP  extends DWLTxnBP{
      DWLControl objDWLControl = null;
    @Override
   
    public Object execute(Object arg0) throws BusinessProxyException{
        // TODO Auto-generated method stub
       
           Object objResponse = null;
       
        try{
        System.err.println("Inside execute...");
        DWLTransactionPersistent objDWLTransactionPersistent = (DWLTransactionPersistent) arg0;
        objDWLControl = objDWLTransactionPersistent.getTxnControl();
        objResponse = processBusinessObject(objDWLTransactionPersistent);
       
        System.err.println("Reached..here..");
        }
       
        catch (Exception objException) {
             objException.printStackTrace();
             
           
         }
        return objResponse;
        //return super.execute(arg0);
    }
   
   
    private Object processBusinessObject(
            DWLTransactionPersistent objDWLTransactionPersistent)
            throws Exception {
        TCRMResponse resAddContract = null;
        DWLCommon objTxnTopLevelObject = (DWLCommon) objDWLTransactionPersistent
        .getTxnTopLevelObject();
        System.err.println("Top Level Object---- "+objTxnTopLevelObject.getClass().toString());
        if ((objTxnTopLevelObject instanceof TCRMContractBObj)) {
       
        System.err.println("Top Level Object instanace of TCRMContractBObj ");
       
        TCRMContractBObj ourTCRMContract=(TCRMContractBObj)objTxnTopLevelObject;
       
       
        XContractBObjExt xContractBobj= (XContractBObjExt)objTxnTopLevelObject;
        System.err.println("Club card Number"+xContractBobj.getXClubCardNbr());
        System.err.println("Line of Business---"+ourTCRMContract.getLineOfBusiness());
        resAddContract=doAddContract(ourTCRMContract);   
        }else{
            System.err.println("Top Level Object NOT instanace of TCRMContractBObj ");
           
           
        }
       
       
       
        return resAddContract;   
    }
   
   
public TCRMResponse doAddContract(TCRMContractBObj ourTCRMContract){
       
   
        System.err.println("In doAddContract()");
        TCRMResponse resAddContract = null;
        //XContractBObjExt xcontract =new XContractBObjExt();
        final String TXN_ADDCONTRACT="addContract";
       
        try {
            resAddContract =  executeAddContract(TXN_ADDCONTRACT,ourTCRMContract);
        } catch (BusinessProxyException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    /*   
        try{
           
           
            if(ourTCRMContract.getXClubCardId() != null){
                System.out.println("XML :::"+objInputXContractBObjExt_dup.toXML());
                resAddContract =  executeAddContract(TXN_ADDCONTRACT,objInputXContractBObjExt_dup);
            }
        }catch (Exception e) {
            System.out.println("Exception in doAddCOntract");
            e.printStackTrace();
        }*/
        return resAddContract;
    }
   
    public TCRMResponse executeAddContract(final String TXN_ADDCONTRACT, final TCRMCommon topLevelObj) throws BusinessProxyException{
        TCRMResponse resExecuteAddContract = null;
        try{
       
        System.err.println("IN executeAddContract()");
       
       
        DWLTransactionPersistent dtpObj = new DWLTransactionPersistent();
       
        //System.out.println("objDWLControl :::"+objDWLControl.toString());
        dtpObj.setTxnControl(objDWLControl);
        dtpObj.setTxnTopLevelObject(topLevelObj);
        dtpObj.setTxnType(TXN_ADDCONTRACT);
       
        resExecuteAddContract = (TCRMResponse) super.processPersistentObject(dtpObj);
       
        }
        catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return resExecuteAddContract;
       
    }
   
   
   

}

One thing to remember is to change the  DWLServiceControllerTester class in the XML tester project.

//Composite MDM Service Hashmap
        context.put("TargetApplication", "tcrm");
        context.put("RequestType", "standard");
        context.put("ResponseType", "standard");
        context.put("CompositeTxn", "true");
        context.put("CompositeParser", "DWLService");
        context.put("CompositeConstructor", "DWLService");
        context.put("OperationType", "all");


References:
1)MDM Developer Guide.
2)http://www.ibm.com/developerworks/forums/thread.jspa?threadID=328058&tstart=0













Wednesday, April 14, 2010

IBM MDM Devlopment Environment Setup

I installed IBM Rational Software Architect 7.0.0.0 in my machine and updated it to version 7.0.0.6 using fix pack.
To set up the MDM Development & Test environment you need to install the MDM WorkBench in your RSA.This can be done by pointing to the location of the MDM Workbench installable through Help->SoftwareUpdates -> Find & Install.

Keep the MDM distribution file ready with you.

Open up your RSA & give a location for the workspace you are going to set up.
There are a few pre installation steps
1)Window->Preference->General->Capabilities
Enable All

2)Server->Launching->Uncheck Automatically publish when starting server.

3)Java ->InstalledJRE ->Point towards C:\IBM\SDP70\runtimes\base_v61\java\jre


Now we are ready for the actual workspace setup.
From RSA

File ->New -> Other->MDM Workbench -> MDM Development & Test Environment.

















Our next step will be select the operations we are going to perform. 

Initially we will select a few .
Let us select the first four.
On click of Next we will be allowed to perform the Websphere Configuration
Create a new server profile by clicking the Create Profile.The profile management tool will pop up.Go for Advanced Profile creation. No need to enable admin security & register as an admin service.

Provide the path to the MDM distribution file.

The next screen will help you to provide the DB information .For Database home  browse to the SQLLIB/java direction of the db2 installation.Username should be db2admin.

Any way in this step we are not creating the DB.Go ahead & finish the first four steps.
After that logoff  & login as db2admin .Check the Create MDM Server Database alone step.


The progress..


Now login back to your user id & proceed with the remaining steps.



After the Deploy MDM Server Configuration Webspher profile check in the APPSOFTWARE & APPDEPLOYMENT tables for entries.
Check the logs alsoe.One this is successfully done go ahead with the validate installation.This will execute the XML's that are present in the InstallVerfication project.Go ahead and check the CONTACT & other corresponding tables  for entries which assures your installation is a success.