More attribute transformation methods

You can perform attribute transformations interactively in the following ways:

This section describes how to implement the following kinds of custom transformations:

Content-based logic

Customer.CustomerStatus = 'Inactive' 
if SAP_CustomerMaster.DeleteInd = 'X'. 

Otherwise, CustomerStatus = 'Active'.

You can create a Custom transformation and write the entire piece of code to implement the content-based logic yourself. However, a better approach is to start by creating a Move transformation between DeleteInd (in the SAP_CustomerMaster object) and CustomerStatus (see "Copying a source attribute to a destination attribute" for the procedure to move attributes).

As a result, Map Designer generates the move-transformation, as shown in the following sample code:

{
   Object _cw_CpBTBSourceValue = null;
 
   //
   // RETRIEVE SOURCE
   // ---------------
   //
   // Retrieve the source value from the source business object and 
   // place it in a local variable for code safety. 
   //
   _cw_CpBTBSourceValue = ObjSAP_CustomerMaster.get("DeleteInd");
 
   //
   // SET DESTINATION
   // ---------------
   //
   // Put the source value into the destination business object
   // attribute.
   //
   {
      Object _cw_SetSrcVal = _cw_CpBTBSourceValue;
      BusObj _cw_SetDestBusObj = ObjCustomer;
      String _cw_SetDestAttr = "CustomerStatus";
 
      //
      // Set the destination value only if neither
      // source nor destination is null.
      //
      if ((_cw_SetSrcVal != null) && (_cw_SetDestBusObj != null))
      {
         if (dataValidationLevel >= 1)
         {
            if (!_cw_SetDestBusObj.validData(_cw_SetDestAttr, _cw_SetSrcVal))
            {
               String warningMessage = 
"Invalid data encountered when attempting to set the value of the
\'_cw_SetDestAttr\' attribute of BusObj \'_cw_SetDestBusObj\' while running 
map \'" + getName() + "\'.  The invalid value was \'" + _cw_SetSrcVal 
+ "\'.";
               //
               // Log a warning about this failure.
               //
               logWarning(warningMessage);
               if (failOnInvalidData)
               {
                  //
                  // Fail the map execution with a warning message.
                  //
                  throw new MapFailureException(warningMessage);
               }
            }
         }
// SECTION THAT NEEDS TO BE UPDATED WITH THE LOGIC
 
      if (_cw_SetSrcVal != null)
         {
         if (_cw_SetSrcVal instanceof BusObj)
            {
            //
            // Since BusObjs are not immutable, we need to make
            // a copy of the source object before actually
            // putting it into the destination attribute.
            //
            _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr,
               ((BusObj)_cw_SetSrcVal).duplicate());
            }
         else if (_cw_SetSrcVal instanceof BusObjArray)
            {
            //
            // Since BusObjs are not immutable, we need to make
            // a copy of the source object before actually
            // putting it into the destination attribute.
            //
            _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr,
               ((BusObjArray)_cw_SetSrcVal).duplicate());
            }
         else
            {
            //
            // Since our version of simple data types are immutable in
            // Java (Strings included), we do not have to make a copy
            // of the source value here.
            //
            _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr, _cw_SetSrcVal);
            }
         }
      }
   }
}
 
// HERE IS THE MODIFIED CODE
 
   if (_cw_SetSrcVal != null)
      {
      if (((String)_cw_SetSrcVal).equals("X")) 
         _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr, "Inactive");
      else
         _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr, "Active");
      }
 
      }
   }
}

Select Save from Activity Editor File menu to save the changes.

Verb-based logic

Customer.CustomerStatus = 'Inactive' if Verb = 'Create'. Otherwise, CustomerStatus = 'Active'.

Follow the procedure in Content-based logic, but use the following conditional statement to replace the section of the generated code:

// HERE IS THE MODIFIED CODE 
if (_cw_SetSrcVal != null)
   {
   if (ObjSAP_CustomerMaster.getVerb() .equalsIgnoreCase("Create"))
      _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr, "Inactive"); 
   else
      _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr,"Active");

Providing default values if source data Is missing

Map SAP_CustomerMaster.State into Customer.CustomerAddress.State. If SAP's state is missing, default to CA.

Notice that before the destination attribute is set to the source value, the code checks if the source attribute is not equal to null.

Example: In this example, if the source data is missing, set the destination attribute to a default value.

Start by moving SAP_CustomerMaster.State into Customer.CustomerAddress.State. Change the condition statement to the following:

// HERE IS THE MODIFIED CODE 
if (_cw_SetSrcVal != null)
   _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr, _cw_SetSrcVal);
else
   _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr, "CA");
_cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr, "CA");

Tip:
If you started the coding by copying the source attribute into the destination attribute, the line of code that sets the default value has to be typed twice. This is because the code that is generated when the source attribute is moved into the destination attribute checks twice that the source attribute is not null. Thus, you must enter the default value.

Logic based on calling context

When you need to check for the value of the calling context, use the built-in variable strInitiator, which is of type String.

Example: To check if the calling context is EVENT_DELIVERY, use the following statement:

if (strInitiator.equals(MapExeContext.EVENT_DELIVERY))
//rest of the code

Forcing a map to fail if the source data Is missing

Map SAP_CustomerMaster.State into Customer.CustomerAddress.State. If SAP's state is missing, stop the map from executing.

Start by moving SAP_CustomerMaster.State into Customer.CustomerAddress.State. Then add one more if() statement to check if the State attribute for SAP is equal to null. The generated code looks like the following:

{
   Object _cw_CpBTBSourceValue = null;
 
   //
   // RETRIEVE SOURCE
   // ---------------
   // 
   // Retrieve the source value from the source business object and
   // place it in a local variable for code safety.
   //
   _cw_CpBTBSourceValue = ObjSAP_CustomerMaster.get("State");
 
   //
   // SET DESTINATION
   // ---------------
   // 
   // Put the source value into the destination business object
   // attribute.
   //
   {
      Object _cw_SetSrcVal = _cw_CpBTBSourceValue;
      BusObj _cw_SetDestBusObj = ObjCustomer;
      String _cw_SetDestAttr = "CustomerAddress.State";
   // New code
   if (_cw_SetSrcVal == null) 
      {
      String errorMessage = "Data in the state attribute is missing";
      logError(errorMessage);
      //
      // Fail the map execution with a warning message.
      //
      throw new MapFailureException(errorMessage);
      }
   // End of new code
 
   //
   // Set the destination value only if neither
   // source nor destination is null.
   //
   else if ((_cw_SetSrcVal != null) && (_cw_SetDestBusObj != null))
      {
      if (dataValidationLevel >= 1)
         {
         if (!ObjCustomer.validData("CustomerAddress.State", _cw_SetSrcVal))
            {
            String warningMessage = 
"Invalid data encountered when attempting to set the value of 
the \"CustomerAddress.State\" attribute of BusObj \'ObjCustomer\' 
while running map \'" + getName() + "\'.  The invalid value 
was \'" + _cw_SetSrcVal + "\'.";
 
            //
            // Log a warning about this failure.
            //
            logWarning(warningMessage);
            if (failOnInvalidData)
               {
               //
               // Fail the map execution with a warning message.
               //
               throw new MapFailureException(warningMessage);
               }
            }
         }
 
      if (_cw_SetSrcVal != null)
         _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr, _cw_SetSrcVal);
 
      }
   }
}

If the map is run and the State attribute is not set, an error message is produced in both a dialog window and on the server screen. The message on the server screen is similar to the following:

[1999/09/22 17:58:51.008] [Server] 
Sub_SaCwCustomerMaster: Error Data 
in the state attribute is missing

The map stops executing.

Tip:
Use the following code to display the actual error message generated by the system on a map failure:
try 
   {
   // your code
   }
catch (Exception e) 
   {
  throw new MapFailureException(e.toString());
   }

Logging messages from a message file

Notice how the example in Forcing a map to fail if the source data Is missing uses the logError() method to display the error message on the screen. You can use messages provided in the generic messages file, CWMapMessages.txt, which is stored in \DLMs\messages. See Appendix A, Message files, for more information about message files.

CWMapMessages.txt has the following format:

# critical data is missing error
10
Data in the {1} attribute is missing. Map execution stopped.
# Another error
11
Another error message

Notice that instead of {1} you can use the word State to correspond directly to the error that needs to be displayed. If implemented, however, the message is no longer generic. If another attribute also has critical data, you need another message in the message file specific to that particular attribute.

Note:
Do not modify the CwMapMessages.txt file. If you need to write your own messages, enter them in the Messages tab of Map Designer, which creates a map-specific error message file named mapName_locale.txt (where mapName is the same name as the map), for example, mapName_en_US.txt. The server saves this message file in the directory \DLMs\messages after deployment.

To display message #10, use the following code:

logWarning(10, "State");

The word State replaces {1} in the message text.

The following message is displayed in the InterChange Server log file:

[1999/09/23 10:17:43.648] [Server] 
Sub_SaCwCustomerMaster: 
Warning 10: Data in the State attribute is missing. 
Map execution stopped.

Date formatting

The Mapping API provides methods for date formatting in the DtpDate class. Table 61 summarizes the date-formatting methods.

Table 61. Date-Formatting Methods of the DtpDate Class

Date Formatting DtpDate Method
Getting the month name from a date getMonth(), getShortMonth()
Getting the month value from a date getIntMonth(), getNumericMonth()
Getting the day of the month getDayOfMonth(), getIntDay()
Getting the day of the week getDayOfWeek(), getIntDayOfWeek()
Getting the year from a date getYear(), getIntYear()
Getting the hour value getHours()
Getting the minutes value from a date getMinutes(), getIntMinutes()
Getting the seconds value from a date getSeconds(), getIntSeconds()
Getting the number of milliseconds in the date getMSSince1970()
Getting the earliest date from a list getMinDate(), getMinDateBO()
Getting the most recent date from a list getMaxDate(), getMaxDateBO()
Parsing the date according to a specified format DtpDate()
Getting the date in a specified or default format toString()
Reformatting a date to the IBM-generic
date format
getCWDate()
Adding days to date addDays()
Adding weekdays to date addWeekdays()
Adding years to date addYears()
Calculating days between dates calcDays()
Calculating weekdays between dates calcWeekdays()
Comparing dates after(), before()
Using full month names get12MonthNames(), set12MonthNames(), set12MonthNamesToDefault()
Using short month names get12ShortMonthNames(), set12ShortMonthNames(), set12ShortMonthNamesToDefault()
Using weekday names get7DayNames(), set7DayNames(), set7DayNamesToDefault()

Tip:
Always catch DtpDateException. This guarantees that if the date format is invalid, a message is sent to the InterChange Server log.

Using the generic date format

IBM uses the following date format in its generic business objects:

YYYYMMDD HHMMSS

This format is called the generic date format.

Steps for converting to generic date format

To convert an application-specific date to this generic format, use the getCWDate() method of the DtpDate class.

Example: To map the SAP date attribute into a generic date, perform a Copy of the source attribute (the SAP date string) into the destination attribute (the generic date string):

  1. Create a DtpDate object to hold the generic date.

    Copy the source attribute (the SAP date string) into a new DtpDate object (the generic date string) by parsing the SAP date string (YYYYMMDD) with the DtpDate() constructor.

  2. Convert the SAP date string into the generic date format (YYYYMMDD HHMMSS) with the getCWDate() method.
  3. Create the destination attribute and initialize its value to the generic date format with the setWithCreate() method.

The last section of the code should look like this:

// HERE IS THE MODIFIED CODE 
if (_cw_SetSrcVal != null) 
   {
   try 
      {
      DtpDate myDate = new DtpDate((String)_cw_SetSrcVal, "YMD");
      _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr,
      myDate.getCWDate());
      }
   catch (DtpDateException de) 
      { 
      logError(5501); 
      logInfo(de.getMessage());
      }
   }

Example: To map the Clarify date attribute into the generic date, perform a Copy of the source attribute (the Clarify date string) into the destination attribute (the generic date string):

  1. Create a DtpDate object to hold the generic date.

    Copy the source attribute (the Clarify date string) into a new DtpDate object (the generic date string) by parsing the Clarify date string (MM/DD/YYYY HH:MM:SS) with the DtpDate() constructor.

  2. Convert the Clarify date string into the generic date format (YYYYMMDD HHMMSS) with the getCWDate() method.
  3. Create the destination attribute and initialize its value to the generic date format with the setWithCreate() method.

The following code converts the Clarify date into the Generic date:

if (_cw_SetSrcVal != null) 
   {
   try 
      {
      DtpDate myDate = new DtpDate((String)_cw_SetSrcVal, 
         "M/D/Y h:m:s");
      _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr,
         myDate.getCWDate());
      }
   catch (DtpDateException de) 
      { 
      logError(5501); 
      logInfo(de.getMessage());
      }
   }

To map the Generic date into the Clarify format, use the following code:

if (_cw_SetSrcVal != null) 
   {
   try 
      {
      DtpDate myDate = new DtpDate((String)_cw_SetSrcVal, "YMD hms");
      _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr,
      myDate.toString("M/D/Y h:m:s", true));
      }
   catch (DtpDateException de) 
      { 
      logError(5501); 
      logInfo(de.getMessage());
      }
}

Steps for converting from generic date format

To convert from the generic date format to the SAP date format, perform the following steps:

  1. Create a DtpDate object to hold the SAP date.

    Perform a Copy of the source attribute (the generic date string) into a new DtpDate object (the SAP date string) by parsing the generic date string (YYYYMMDD HHMMSS) with the DtpDate() constructor.

  2. Convert the IBM generic date format into the SAP date string (YYYYMMDD) with the toString() method.
  3. Create the destination attribute and initialize its value to the SAP date format with the setWithCreate() method.

The following code fragment shows this generic-to-SAP date conversion:

// HERE IS THE MODIFIED CODE
if (_cw_SetSrcVal != null) 
   {
   try 
      {
      DtpDate myDate = new DtpDate((String)_cw_SetSrcVal, "YMD hms");
      _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr,
      myDate.toString("YMD"));
      }
   catch (DtpDateException de) 
      { 
      logError(5501); 
      logInfo(de.getMessage());
      }
   }

Obtaining the current date

To create a DtpDate object that is initialized with the current system date, use the DtpDate() constructor without any parameters:

DtpDate()

Example: To map the current date into the generic format, use the following code:

//get the current date
DtpDate myDate = new DtpDate();
// format the date to the destination object's format and map
_cw_SetDestBusObj.set(_cw_SetDestAttr, myDate.getCWDate());

To map the current date into the application-specific format, use the following code:

//get the current date
DtpDate myDate = new DtpDate();
// format the date to the destination object's format and map
_cw_SetDestBusObj.set(_cw_SetDestAttr, myDate.toString(
   "application format");

Using Expression Builder for string transformations

When writing transformation code, you may need to build complex Java expressions to reference a particular attribute, manipulate a string, or call an API method. You can enter these expressions manually in Activity Editor, or use Expression Builder to construct the expression interactively. Expression Builder is a utility available from within Activity Editor.

Tip: Alternatively, you can use Activity Editor's Graphical view.

To display Expression Builder, place the cursor at the position in Activity Editor where you want to insert the expression and do one of the following:

Figure 89 identifies the main components of Expression Builder.



Figure 89. Expression Builder dialog

Note:
In the API list, the number 1 refers to the object selected from the far left window and the number 2 refers to the object selected from the middle window, if there is an object present. When you insert the API, pairs of brackets surround variables (<<variable>>). You must replace the brackets and the variable with a value.

This section describes how to use Expression Builder to perform the following kinds of string transformations:

Steps for converting to uppercase text

Move SAP_CustomerMaster.CustomerName into Customer.AccountOpenedBy and convert all letters to uppercase text.

To use the toUpperCase() string manipulation functions, perform the following steps:

  1. Perform a Move transformation from SAP_CustomerMaster.CustomerName into Customer.AccountOpenedBy.
  2. Open the Activity Editor window by double-clicking in the Transformation Rule column associated with Customer.AccountOpenedBy. In Activity Editor, scroll down to the point where the destination is set to the source data. Change it to contain just the following code:
    if (_cw_SetSrcVal != null)
       {
       //
       // Since our version of simple data types are immutable in
       // Java (Strings included), we do not have to make a copy
       // of the source value here.
       //
       _cw_SetDestBusObj.setWithCreate(
       _cw_SetDestAttr, _cw_SetSrcVal);
       }
    

    The _cw_SetSrcVal variable contains SAP.CustomerName and _cw_SetDestAttr contains AccountOpenedBy.

  3. Convert CustomerName to uppercase before copying it into AccountOpenedB.

    If you know the method to use, add it to the line of code above; otherwise, you can use Expression Builder to help you find the correct method. To do this:

    1. Copy (Ctrl+C) _cw_SetSrcVal.
    2. Highlight _cw_SetSrcVal (this code will be replaced with the code generated by Expression Builder) and select Expression Builder from the Tools menu.
    3. Select String in the Main Categories list.
    4. Select the method toUpperCase() from the list of String APIs.
    5. Click Insert API.
    6. When this method is displayed in the top window, replace the word "string," which is a placeholder, with the word _cw_SetSrcVal that you copied earlier.
    7. Click OK.

      Result: The method call is inserted into the code.

    8. Select the Save option from the File menu to save the code.

Using string manipulation methods

The following string transformation uses string manipulation methods (such as length() and substring()) to move SAP_CustomerMaster.AddressLine1 into Customer.CustomerAddress.AddressLine1 and AddressLine2:

Steps for performing the string transformation

To perform this string transformation, follow these steps:

  1. Perform a Move transformation of AddressLine1 into CustomerAddress.AddressLine1.
  2. Open the Activity Editor window of AddressLine1 and scroll down to the point where the destination is set to the source data. Change it to contain the following code:
    if (_cw_SetSrcVal != null)
       //
       // Since our version of simple data types are immutable in
       // Java (Strings included), we do not have to make a copy
       // of the source value here.
       //
       {
       _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr,
          _cw_SetSrcVal);
       }
    

    The _cw_SetSrcVal variable contains SAP.AddressLine1, and _cw_SetDestAttr contains CustomerAddress.AddressLine1.

  3. Check the length of SAP.AddressLine1 and either map the entire string into CustomerAddress.AddressLine1 or map the substring of SAP.AddressLine1 that precedes the comma.

    You can either modify the code yourself or use Expression Builder. In either case, use the methods length(), substring(int, int), substring(int), and indexOf(int) methods of the String class.

  4. Change the code to the following:
    if (_cw_SetSrcVal != null)
       {
       // first check the length of _cw_SetSrcVal
       if (((String)_cw_SetSrcVal).length() < 10) 
          {
          // if it is less then 10, map it to AddressLine1
          _cw_SetDestBusObj.setWithCreate(
             _cw_SetDestAttr, _cw_SetSrcVal);
          }
       else 
          {
          // if the length is not less than 10, search for comma
          int index = ((String)_cw_SetSrcVal).indexOf(",");
     
          // if comma is found, take a substring of _cw_SetSrcVal up to
          // the comma and map it to AddressLine1
          if (index != -1)
             _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr,
                ((String)_Cw_SetSrcVal).substring(0, index));
             // if comma is not found, take first 9 characters of
             // _cw_SetSrcVal and map them to AddressLine1
          else
             _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr,
                ((String)_Cw_SetSrcVal).substring(0, 9));
          }
       }
    
  5. Move SAP.AddressLine1 into CustomerAddress.AddressLine2. Modify the bottom part of the code to contain the following:
    if (_cw_SetSrcVal != null)
       {
       // first check the length of _cw_SetSrcVal
       if (((String)_cw_SetSrcVal).length() >= 10) 
          {
          // if the length is not less than 10, search for comma
          int index = ((String)_cw_SetSrcVal).indexOf(",");
          // if comma is found, take a substring of _cw_SetSrcVal after 
          // the comma and map it to AddressLine2
     
          if (index != -1)
             _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr,
                ((String)_Cw_SetSrcVal).substring(index + 1));
             // if comma is not found, take all characters of 
             // _cw_SetSrcVal starting at the 10th and map them to
             // AddressLine1
     
          else
             _cw_SetDestBusObj.setWithCreate(_cw_SetDestAttr,
                   ((String)_Cw_SetSrcVal).substring(9));
          }
       }
    

Source data validation

If you write code yourself, make sure that the source data is not null or blank. To check whether the source attribute is null, use one of the following:

To check whether the source attribute is an empty string, do the following:

Copyright IBM Corp. 1997, 2004