Skip Headers

Oracle® Application Server ProcessConnect User's Guide
10g (9.0.4)

Part Number B12121-01
Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Go to previous page Go to next page

14
Advanced Transformations Design

This chapter describes how to design advanced transformations. Common transformation errors and transformation limitations are also described.

This chapter contains these topics:

Implicit Conversion Support

Transformation supports implicit conversions between datatypes. Implicit datatype conversions are carried out between datatypes without any explicit datatype conversion function being called. This enables you to use variables and parameters of one type where another type is expected.

The following implicit datatype conversions are supported by transformation:

These conversions are allowed since there is no loss of data. Implicit conversion is applicable to both source and target parameters.

"Example 1: Implicit Conversion for Source and Target Parameters" and "Example 2: Implicit Conversion of Source and Target Parameters in the Same Datatype Transformation Map" illustrate the implicit conversion scenarios in transformation maps. These examples help you identify the correct datatype transformation map to invoke in places where implicit conversions are allowed. An entire list of implicit and explicit conversions allowed by transformation can be viewed in Table 14-1.


Note:

For source parameters, the implicit conversion rules are applied from a datatype of event type parameters or datatype parameters or map variables to a datatype of a source parameter of the datatype transformation map. For target parameters, the rules are applied vice versa (that is, implicit conversion rules are applied from a datatype of a source of the datatype transformation map to a datatype of event type parameters or datatype parameters or map variables.


Example 1: Implicit Conversion for Source and Target Parameters

In Figure 14-1, the total of Invoice, which is of type double, gets copied to the total of PO, which is of type string.

Figure 14-1 Implicit Conversion of Source and Target Parameters

Text description of ipusr095.gif follows

Text description of the illustration ipusr095.gif

To perform the transformation operation in Figure 14-1, you must select the appropriate copy datatype transformation map to be invoked. In this case, there are two valid datatype transformation maps that can be invoked:

Selecting the first copy transformation map results in implicit conversion of a source parameter. In this case, the total member of Invoice of type double is bound to the source parameter from of the copy datatype transformation map of type string. This is a valid binding since a double datatype can be implicitly converted to a string datatype. The target binding does not need conversion since their datatypes are the same.

Selecting the second copy transformation map results in implicit conversion of a target parameter. In this case, the total member of PO of type string is bound to a target parameter of a datatype transformation map of type double. This is a valid binding since a double datatype can be implicitly converted to a string datatype. The source parameter does not need conversion since their datatypes are the same.

Figure 14-1 illustrates two important points:

Mapping Logic

{
   ...
   copy (from= Invoice::/total) -> (to= PO::/total);
   ...
}

Example 2: Implicit Conversion of Source and Target Parameters in the Same Datatype Transformation Map

In Figure 14-2, the price of Line-Item, which is of type float, is multiplied with quantity, which is of type integer, to obtain the total. The total obtained is copied to the item-total of Item which is of type string.

Figure 14-2 Implicit Conversion of Source and Target Parameters in the Same Datatype Transformation Map

Text description of ipusr096.gif follows

Text description of the illustration ipusr096.gif

To perform this transformation, the following datatype transformation map is invoked:

multiply(first=float, second=float -> result=float) ;

In this case, price is bound to the first source parameter for the datatype transformation map and quantity to the second source parameter. For the target parameter result, the item-total is bound. The quantity of Line-Item, which is of type integer, gets implicitly converted to datatype float of the second parameter. The result, which is of type float, is implicitly converted to a string type.

Mapping Logic

	
{
   ...
   multiply (first = Line-Item::/price, second= Line-Item::/ Quantity) -> (to=
     Item::/Item-Total);
...
}

Invalid Case

In Figure 14-2, the code of Line-Item, which is of type string, is copied to the code of Item, which is of type integer. To perform this transformation invocation, the following copy datatype transformation map is invalid since, there is no implicit conversion from the source item, code of Line-Item, which is of type string to the source of the copy datatype transformation map, which is of type integer.

copy(from=integer -> to=integer);

Invalid Mapping Logic

{
   ...
   copy (from= Line-Item::/Code) -> (to= Item::/Code);
   ...
}

To invoke the copy datatype transformation map, you must first convert the code of Line-Item to a value of datatype integer. Invoking the datatype transformation map stringToInteger with the code bound to the source and a map variable (for example, integerValue of type integer bound to the target) results in the required conversion. This map variable, integerValue, can then be substituted in place of the source item code in this datatype transformation map.

Valid Mapping Logic

{
   ...
   stringToInteger(sourceString= Line-Item::/Code) -> (resultInteger=
      integerValue);
   copy (from = integerValue) -> (to= Item::/Code);
...
}

Table 14-1 shows the datatype conversion matrix of allowable implicit and explicit conventions. The following naming conversions are used.

Common User Errors in Transformation Design

This section describes common user errors in designing transformations.

This section contains these topics:

Not Checking for the Existence of an Optional Datatype Member

You must check for the existence of an optional datatype member of any datatype in the instance. If the member is not present in the source instance, and there is a rule for copying the source item to the target item, an empty element is created in the target instance.

Example

Under datatype Address, street1 is an optional member.

Incorrect Design

The incorrect design is to copy the source without checking for the existence of the datatype member in the source instance. The following transformation rule:

copy( from=street1 -> to= street1)

creates an empty street1 element in the target instance. For example, the source instance:

<Address> 
</Address>

results in the following target instance:

<Address>

<street1/>
</Address>

Correct Design

Use the Exists function to check for existence of the optional datatype member in the instance. This prevents having an empty element in the target instance:

 if ( Exists ( street1 ) ) 
{
    copy( from =street1 -> to= street1);
 }

Not Checking for the Existence of a Datatype Member of the Model Group Choice

Check for the existence of any datatype member of a datatype whose model group is choice in the instance as an optional member. If the member is not present in the source instance, an empty element is created in the target instance.

Example

The street1 and street2 datatypes under datatype Address are choice members.

Incorrect Design

The incorrect design is to copy without checking for the existence of the members in the source instance. The following transformation rule:

copy( from=street1 -> to= street1);
copy( from=street2 -> to= street2);

creates an empty street1 or street2 element in the target instance. For example, the source instance:

<Address>

<street1>Oracle Parkway</street1> 
</Address>

or

<Address>

<street2>Oracle Parkway</street2> 
</Address>

results in the following target instance:

<Address>

<street1>Oracle Parkway</street1>
<street2/>
</Address>

or

<Address>

<street1/>
<street2>Oracle Parkway</street2> 
</Address>

Correct Design

Use the Exists function to check for the existence of an optional datatype member of a datatype in the instance. This avoids the creation of an empty element in the target instance.

Mapping Logic

if ( Exists ( street1 ) ) 
{

copy( from=street1 -> to= street1);
} if ( Exists( street2 ) ) {
copy( from=street2 -> to= street2);
}

See Also:

"Creating a Complex Datatype" for conceptual details about the choice model group

Not Defining an Iterator to Access a Datatype Member with Multiple Occurrences

If you have a datatype member of multiple occurrences, you must access it with an iterator. Otherwise, you receive a runtime error if there are multiple elements in the instance. This error typically occurs when you either do not know that the member being accessed has multiple occurrences, or you wrongly assume that you are accessing the first (or last) instance of the datatype member by default.

Example

Target Address has multiple streets mapped from multiple source streets in source Addr.

Incorrect Design

You are unaware that Addr has source streets (st) of multiple occurrences. For example:

CopyAddrToAddress (Addr fromAddr -> Address toAddress) 
{

copy(from=fromAddr::./st -> to=toAddress::./street);
}

You receive a runtime error if st appears multiple times in the Addr instance.

Correct Design

The correct design is to use an iterator:

CopyAddrToAddress (Addr fromAddr -> Address toAddress) 
{

for each(streets=fromAddr::./st) {
copy(from=iterator streets -> to=toAddress::./street)
} }

Not Creating a Submap to Populate a Multiple Occurrence Target Member

Transformation mandates the invocation of a separate user-defined datatype map from within an iterator to map a complex target member of multiple occurrences from a complex source member of multiple occurrences. A common error is to create direct mappings to complex target members within an iterator without invoking a separate datatype transformation map. In this case, the execution results in creation of a target structure that is unintended and does not match the corresponding type definition. This causes failure in native event validation or in later transformations.

Example

The target purchase order with multiple complex members of type item is mapped from source Invoice with multiple complex members of type line-item. Each target item's content (identifier, quantity, and cost) is mapped from the corresponding source line-item content (id, qty, and cost).

Figure 14-3 shows this scenario.

Figure 14-3 Populating a Multiple Occurrence Target Member

Text description of ipusr081.gif follows

Text description of the illustration ipusr081.gif

Incorrect Design

The incorrect design is to create direct mappings to complex target members within an iterator without invoking a separate datatype transformation map, as depicted in the following mapping logic:

for each (lineItems = inv::./line-item)
{

copy (from=iterator line-items::./id -> to=po::./item/identifier); 
copy (from=iterator line-items::./qty -> to=po::./item/quantity); 
}

This creates a single item with as many identifier and quantity values as the number of source line-items. For example, this source instance:

<invoice> 

<line-item>
<id>001</id>
<qty>1</qty>
</line-item>
<line-item>
<id>002</id>
<qty>2</qty>
</line-item>
</invoice>

results in the following target instance:

<po>
  <body>
     <item> 
          <identifier>001</identifier>
          <identifier>002</identifier>
          <quantity>1</quantity>
          <quantity>2</quantity>
     </item>
  </body>
</po>

Correct Design

An invocation of a separate datatype transformation map is required within the iterator to fully populate the target item before adding to the target PO. This is so that it does not require updating with child content (for example, quantity and cost) later.

The datatype transformation map invoked within the iterator maps the members of the target item from the members of the source line-item. For example:

copyInvoiceToPO (Invoice inv -> PO po)
{
  ....
  for each (lineItems = inv::./line-item) {
    copyLineItemToItem (lineItem=iterator line-items -> item=po::./item);
  }
  ....
}

copyLineItemToItem (lineItem srcLineItem -> item targetItem) 
{
    copy (from=srcLineItem::./id -> to= targetItem::./identifier); 
    copy (from=srcLineItem::./qty -> to= targetItem::./quantity); 
    copy (from=srcLineItem::./cost -> to= targetItem::./cost);
}

Incrementally Populating a Complex Datatype Using Submaps

Transformation does not support incremental populating of a complex datatype using submaps. If you invoke a submap that passes in a complex datatype as a target parameter, a new instance of that complex datatype is created by that submap invocation. If the same complex datatype parameter is passed to several submaps, a new instance is created every time. If using submaps, therefore, populate the complex datatype only once. It is permissible to populate the members of the complex datatype one-by-one by calling submaps. The error typically occurs when you bunch several members together and create submaps to populate those sets of members.

Example

You want to transform a detailed address to a summarized address. A detailed address has the following format:

<address>

<street1>106 Main Street</street1>
<street2>Apt #200</street2>
<city>Anytown</city>
<state>CA</state>
<zip>10011</zip>
</address>

A summarized address has the following format:

<address>

<street>106 Main Street, Apt #200<street>
<location>Anytown, CA 10011</location>
</address>

Incorrect Design

The incorrect design is to pass the same target address to two submaps expecting that they populate different parts of the address.

mapAddress (DetailedAddress sourceAddr -> SummaryAddress targetAddr)
{


mapStreetAddress(addr1=sourceAddr -> addr2=targetAddr);
mapLocation(addr1=sourceAddr -> addr2=targetAddr);
} mapStreetAddress(DetailedAddress addr1 -> SummaryAddress addr2) {
//concatenates street1 and street2 and populates the 
// street in addr2
} mapLocation(DetailedAddress addr1 -> SummaryAddress addr2) {
// concatenates city, state and zip and populates the 
// location in addr2
}

Correct Design

The correct design is to pass only the members of the target address to the submaps.

mapAddress (DetailedAddress sourceAddr -> SummaryAddress targetAddr)
{


formStreetAddress(addr1=sourceAddr ->
street=targetAddr::./street);
formLocation(addr1=sourceAddr ->
location=targetAddr::/location);
} formStreetAddress(DetailedAddress addr1 -> string street) {
// concatenates street1 & street2 and returns result
} formLocation(DetailedAddress addr1 -> string location) {
// concatenates city, state & zip and returns result
}

Not Populating Mandatory Target Members

All mandatory datatype members of a target datatype must be populated. Otherwise, transformation generates an invalid target instance.

Example

street1 is a mandatory member under datatype Address.

Incorrect Design

The incorrect design is to have no rule defined or no rule executed at runtime for the mandatory datatype member of the target datatype model.

Correct Design

There is currently no alternative other than ensuring that all target mandatory datatype members get populated with the map. The user interface tool shows the members mapped by a transformation map that helps determine if any mandatory target member remains unmapped.

Transformation Design Limitations

This section describes transformation limitations.

This chapter contains these topics:

Only Global Map Variables are Supported

The Oracle Application Server ProcessConnect user interface tool currently only supports global scope variables within transformation statements. You cannot define a variable within a transformation block in a map (for example, within a transformation iterator or a transformation condition). A map variable is accessible throughout the map and can be used from within any block in the map.

Example

Assume that you must compute the total cost of all the line-items within an invoice (if there are any line-items in the source). You go over each of these line-items and add the price of each into a temporary variable that is initialized to zero. Finally, you copy the total price into the totalCost field within the purchase order (PO).

copyInvoicePOMap [DatatypeMap](AppEventDatatype  Invoice invoice -> 
BusinessEventDatatype PO po)
{
 if(Exists(invoice::./lineitem) {
int totalPrice;

copy(from=0->to=variable totalPrice);  
for each (lineItems = invoice::./line-item) {
copy(from=line-item::./price -> to=item::./price);     
copy(from=line-item::./quantity -> to=item::./quantity);
add(first=line-item::./price second=variable totalPrice -> 
result=totalPrice);
} copy(from=variable totalPrice->to=po::./totalCost); } }

Workaround

Declare totalPrice outside all transformation blocks within the map; in this case, outside the Exists condition in which it was declared.

copyInvoicePOMap [DatatypeMap](AppEventDatatype  Invoice invoice -> 
BusinessEventDatatype PO po)
{

  int totalPrice;

if(Exists(invoice::./lineitem) {

copy(from=0->to=variable totalPrice);  
for each (lineItems = invoice::./line-item) {

copy(from=line-item::./price->to=item::./price);     
copy(from=line-item::./quantity->to=item::./quantity);
add(first=line-item::./price second=variable totalPrice->result=totalPrice);
} copy(from=variable totalPrice->to=po::./totalCost); } }

Transformation Statements Cannot be Moved in the User Interface Tool

You cannot currently change the position of already-defined transformation statements in the Oracle Application Server ProcessConnect user interface tool. You can only define new rules to add to the end of the list of statements, or inserted within the list of statements.

Example

Assume you have the following set of statements:

for each (lineItems = invoice::./line-item) {
  if ((line-item::./quantity >= 5) OR (line-item::./line-total > 1000)) {

copy(from=line-item::./quantity -> to=item::./quantity);
concat(firstString=variable tmpId,secondString=line-item::./description -> resultString=item::./uid); }

You then decide to copy the field quantity to the target even though the quantity is less than five. This means you must move the related copy operation outside the IF condition. This is not currently possible in the Oracle Application Server ProcessConnect user interface tool.

Workaround

Delete the copy statement from the set of transformation statements. Then, insert a new statement for performing the copy above the IF condition.

No Overwrite Ability for Target Members

After you have populated a member of the target, you cannot overwrite it. To populate any member, you have to invoke some type of rule; since every rule invocation results in a new instance being created, you are creating multiple instances of the member if you invoke the rule multiple times. After you have initialized the member with a given instance, however, you cannot overwrite that instance.

Example

While mapping an invoice to a purchase order, you want to determine whether to apply a discount to the purchase order. You have multiple condition statements that, if true, result in a discount being applied:

if (invoice::./total > X) {

subtractInteger(first=invoice::./total, second=1000, result=po::./total);
} if (invoice::./quantity > Y) {
subtractInteger(first=invoice::./total, second=500, result=po::./total);
} ...

If it is possible that more than one condition can evaluate to true, you receive a result that was not intended. Multiple total elements get created in the purchase order, each with a particular discount applied.

Workaround

The only workaround is to ensure that a particular rule that populates a member gets executed only once. In this example, structure your logic so that the conditions are mutually exclusive (that is, only one of them evaluates to true at runtime).

NOT Operator is Unsupported

This section describes NOT operator workarounds.

Description

You cannot currently use the logical NOT operator while defining condition expressions. The only logical operators supported by transformation are =, !=, <, <=, >, >=, and Exists. To combine simple condition expressions to create more complex ones, the AND and OR operators can be used.

Example

You want rule1 to be invoked if the following condition is true:

NOT((a > 5) OR (b <= 2))

Otherwise, you want rule2 to be invoked. You ideally want to design it as follows:

if (NOT((a > 5) OR (b <= 2))) {

rule1;
} else {
rule2;
}

However, the NOT operator is currently unsupported, and you must design this scenario differently.

Workaround

You can substitute the rules in the IF and ELSE blocks and remove the NOT operator. This results in:

if ((a > 5) OR (b <= 2)) {

rule2;
} else {
rule1;
}

Although this strategy works, it is not useful for the majority of cases where you do not have an ELSE block with which to start. For example, if the original condition is as follows:

if (NOT((a > 5) OR (b <= 2))) {

rule1;
}

you cannot convert this as follows:

if ((a > 5) OR (b <= 2)) {

} else {

rule1;
}

This is because transformation does not permit empty blocks such as the IF block shown in this example.

The workaround is typically to use logical arithmetic to negate the condition. You can use the following rule to negate the condition:

NOT(a OR b) = NOT a AND NOT b 

Therefore:

NOT((a > 5) OR (b <= 2)) -> NOT (a>5) AND NOT(b<=2) -> (a<=5) AND (b>2)

You can write the condition as follows:

if ((a<=5) AND (b>2)) {

rule1;
} else {
rule2;
}

The one case where this logical negation of the condition fails is in the case of the operator Exists. If you want to model the following:

if (NOT(Exists(a))) {

rule1;
}

Use the following workaround:

boolean exists_var;

if (Exists(a)) {

exists_var=true;
} else {
exists_var=false;
} if (exists_var = false) {
rule1;
}

Transformation Iterator Design

This section describes how to design advanced transformation iterator scenarios.

This section contains these topics:

Multiple Occurrence Target Members from Multiple Occurrence Source Members

This section describes structure-preserving mappings. These are mappings in which the datatype structure of the target is exactly the same as that of the source.

Target Member of Scalar Datatype

A multiple occurrence scalar target member is mapped from a multiple occurrence scalar source member.

Example

Target Address has multiple streets mapped from multiple source streets in source Addr, as shown in Figure 14-4.

Figure 14-4 Target Member of Scalar Datatype

Text description of ipusr080.gif follows

Text description of the illustration ipusr080.gif

Mapping Logic

CopyAddrToAddress (Addr fromAddr -> Address toAddress) 
{
  for each(streets=fromAddr::st) {
    copy(from=iterator streets -> to=toAddress::street)
  }
}

Target Member of Complex Datatype

A multiple occurrence complex target member is mapped from a multiple occurrence complex source member.

Example

Target PO with multiple items is mapped from source Invoice with multiple line-items. Each target item's contents (identifier, quantity, and cost) are mapped from the corresponding source line-item content (id, qty, and cost), as shown in Figure 14-5.

Figure 14-5 Target Member of Complex Datatype

Text description of ipusr081.gif follows

Text description of the illustration ipusr081.gif

Mapping Logic

Invocation of a separate datatype transformation map is required within the iterator to fully populate the target item before adding to the target PO.

The datatype transformation map invoked within the iterator maps the members of the target item from the members of the source line-item.

copyInvoiceToPO (Invoice inv -> PO po)
{
  ....
  for each (lineItems = inv::./line-item) {
     copyLineItemToItem (srcLineItem=iterator line-items -> 
       targetItem=po::./item);
  }
  ....
}

copyLineItemToItem (lineItem srcLineItem -> item targetItem) 
{
    copy (from=srcLineItem::id -> to= targetItem/identifier); 
    copy (from=srcLineItem::qty -> to= targetItem/quantity); 
    copy (from=srcLineItem::cost -> to= targetItem/ cost);
}

Different Target Members Mapped from the Same Source Member

A source member with multiple occurrences is mapped to two different target members with multiple occurrences based on a condition. For example, a source invoice has multiple line-items that each have a member called availability. This member's value indicates whether the line-item is in stock or not. The target GroupedPO has a structure where all the in-stock line-items are grouped under inStock and the out of stock items are grouped under outOfStock, as shown in Figure 14-6.

Figure 14-6 Different Target Members Mapped from the Same Source Member

Text description of ipusr082.gif follows

Text description of the illustration ipusr082.gif

Mapping Logic

A condition must be defined within the iteration of the source line-item to complete the mapping to the appropriate target member.

copyInvoiceToPO (Invoice inv -> GroupedPO po)
{
  ....
  for each (line-items = inv::items) {
    if (iterator line-items::availability = 
        'inStock') {
      // copy the line-item to items under inStock 
      copy(from=iterator line-items::name -> to=po::./inStock/item::name);
      ....
     }
     else {
       if (iterator line-items:: availability = 
          'outOfStock') {
        // define the mapping for buyer 
        copy(from=iterator line-items::name -> to=po::./outofStock/item::name);
        ....
       }
     }
    }
}

Nested Multiple Occurrence Members in the Target Datatype

Multiple occurrence target datatype members are of a complex datatype that has additional multiple occurrence members. These target members are mapped from source members having a similar structure of nested multiple occurrences.

Example

Target PO has multiple items that each contain multiple descriptions. PO is mapped from a similarly-structured source Invoice that has multiple line-items. Each line-item has a complex datatype member of multiple occurrences called desc. Each desc has a lang member. Figure 14-7 shows this scenario.

Figure 14-7 Nested Multiple Occurrence Members in Target

Text description of ipusr083.gif follows

Text description of the illustration ipusr083.gif

Mapping Logic

Invocation of a datatype transformation map is required within an iterator over the outer multiple occurrence source member. The invoked datatype transformation map also has another iterator over the nested multiple occurrence source member.

copyInvoiceToPO (Invoice inv -> PO po)
{
  ....
  for each (lineItems = inv::./line-item) {
   copyLineItemToItem (from=iterator line-items -> to=po::./item);
  }
  ....
}

copyLineItemToItem (lineItem srcLineItem -> item targetItem) 
{
    copy (from=srcLineItem::id -> to= targetItem/identifier); 
    copy (from=srcLineItem::qty -> to= targetItem/quantity); 
    copy (from=srcLineItem::cost -> to= targetItem/ cost);
       for each (descs = srcLineItem::desc) {
      copyDescToDescription (from=iterator descs -> to=targetItem::description);
  }
}

copyDescToDescription (desc srcDesc -> description targetDescription) {
    copy (from= srcDesc::lang -> to= targetDescription::lang);

Single Occurrence Target Members from Multiple Occurrence Source Members

This section describes mappings to a single occurrence target member from a multiple occurrence source member that require a way to select the specific source member to be mapped.

Data-Based Condition

A particular multiple occurrence source member is selected based on a condition over the source data and mapped to a single occurrence target member.

Example

Source Invoice has multiple party datatype members with a type value within it indicating the kind of party. The target member has single buyer and seller members.

The target member buyer of target PO is mapped from the source multiple occurrence party of Invoice whose type is set to purchaser. Similarly, seller is mapped from party with a type of supplier, as shown in Figure 14-8.

Figure 14-8 Data-Based Condition

Text description of ipusr084.gif follows

Text description of the illustration ipusr084.gif

Mapping Logic

A condition must be defined within the iterator to verify the type of Party being iterated over for the appropriate mapping.

copyInvoiceToPO (Invoice inv -> PO po)
{
  ....
  for each (parties = inv::party) {
    if (iterator parties::type = 'purchaser') {
      // define the mapping for buyer 
      copy(from=iterator parties::name ->
          to=po::./buyer/name);
      ....
     }
     else {
       if (iterator parties::type = 'supplier') 
        // define the mapping for seller 
        copy(from=iterator parties::name ->
            to=po::./seller/name);
        ....
       }
     }
    }
}

Position-Based Condition

A particular multiple occurrence source member is selected based on its position in the source instance and mapped to a single occurrence target member.

Example

The source Party contains multiple contact information, but only the first contact information is mapped to the target Party that contains only single contact information.

Figure 14-9 shows this scenario.

Figure 14-9 Position-Based Condition

Text description of ipusr085.gif follows

Text description of the illustration ipusr085.gif

Mapping Logic

Transformation does not currently provide access to the position of the current item within the iterator. Therefore, you must explicitly define a map variable to keep track of the first item (contact) in the iteration and copy it to the target.

copy (Party srcParty -> Party targetParty) 
{
  // declare a map variable 
  int iteratorPosition ; 
  ....
  // initialize the map variable 
  copy (from='0' -> to=variable iteratorPosition);
  
  // iterate over the contacts
  for each (contact = srcParty::contact) {
    if (variable iteratorPosition = '0') {
      // copy the current contact being iterated to the target contact  
      copy(iterator contact,targetParty::contact);
      ....
     }
     // increment the iterator position
     add(firstInteger= iteratorPosition, 
       SecondInteger='1' -> 
      to= iteratorPosition);
   }
}

User Discretion - Direct Mapping without an Iteration

Even though the type definition states that a particular source member has multiple occurrences, the actual instances may not have more than one occurrence. In such a case, you can directly copy this source member without using an iterator.

If the instance has multiple occurrences and you have mapped it without using an iterator, you receive a runtime error. Therefore, the usage of this pattern shown in Figure 14-10 is discouraged.

Figure 14-10 User Discretion - Direction Mapping without Iteration

Text description of ipusr086.gif follows

Text description of the illustration ipusr086.gif

Example

As with the previous example, the source Party has member contact information with potential multiple occurrences, but the actual instances always have single occurrences of contact information that is mapped to the target contact.

Mapping Logic

The single source contact is directly mapped to the target contact without use of iterations.

copy (Party srcParty -> Party targetParty) 
{
   copy(srcParty::contact -> targetParty::contact);
   ....
}

Cumulative Computation

The multiple occurrences of a source member are iterated over to perform a cumulative computation (such as summation and average) on the values being iterated over.

Example

Target PO has a totalAmount type that is computed by iterating and summing up all the source line totals, as shown in Figure 14-11.

Figure 14-11 Cumulative Computation

Text description of ipusr087.gif follows

Text description of the illustration ipusr087.gif

Mapping Logic

A map variable is declared for invoiceTotal. Iteration is defined over a source line-item within which each line-total is added to invoiceTotal. At the end of the iteration, the invoiceTotal is copied to the target totalAmount.

copyInvoiceToPO (Invoice inv -> PO po)
{
  // the map variable for the total
  int invoiceTotal; 
  ...

  for each (lineItems = inv::./line-item) {
   // add line-total to invoice total
   add(firstInteger=iterator line-items::line-total) , 
       SecondInteger=variable invoiceTotal -> 
      to= variable invoiceTotal);
  }
  //copy the computed invoice total to the po totalAmount
  copy(from=variable invoiceTotal -> 
      to=po:totalAmount);
}

Structure Flattening Iterations (Nested Iterators)

This scenario refers to the case where a multiple occurrence complex datatype has further multiple occurrence members. Such nested source members are mapped to a target with only one level of multiple occurrence members; that is, the multiple occurrence target datatype member does not have any further child members with multiple occurrences. Such mappings require the source nested structure to be flattened out by a Cartesian product of the source members.

Example

The source ComputersByVendor has multiple vendor types that each have a list of the supported operating system types (identified by OS in the following example). The target has a flattened list of computer types with each computer having the vendor and OS.

Sample Source Instance:

<computersByVendor>
   <vendor>
      <name>Gateway</name>
       <OS>Windows</OS>
       <OS>Linux</OS>
   </vendor>
   <vendor>
      <name>Dell</name>
       <OS>Windows</OS>
       <OS>Linux</OS>
   </vendor>
   <vendor>
      <name>Sun</name>
       <OS>Linux</OS>
       <OS>Solaris</OS>
    </vendor>
  </computersByVendor>

Sample Target Instance:

<computerFlatList>
  <computer>
     <Vendor><name>GateWay</name></Vendor>
     <OS><name>Windows</name></OS>      
  </computer>
  
<computer>
     <Vendor><name>GateWay</name></Vendor>
     <OS><name>Linux</name></OS>      
  </computer>

  <computer>
     <Vendor><name>Dell</name></Vendor>
     <OS><name>Windows</name></OS>      
  </computer>

  <computer>
     <Vendor><name>Dell</name></Vendor>
     <OS><name>Linux</name></OS>      
  </computer>
  <computer>
     <Vendor><name>Sun</name></Vendor>
     <OS><name>Linux</name></OS>      
  </computer>

  <computer>
     <Vendor><name>Sun</name></Vendor>
     <OS><name>Solaris</name></OS>      
  </computer>
</computerFlatList>

Figure 14-12 shows this scenario.

Figure 14-12 Structure Flattening Iterations

Text description of ipusr088.gif follows

Text description of the illustration ipusr088.gif

Mapping Logic

This mapping requires the definition of an iterator over the vendor that contains another (nested) iterator over all the operating system (OS) types of the current vendor.

A map invoked within the inner iterator can perform the Cartesian product by accessing the current OS name (from the inner iterator) and the current vendor name (from the outer iterator) and invoke a datatype transformation map that creates a target computer with the OS name and vendor name.

copyFlatComputerListToComputersByVendor 
   (ComputersByVendor computerByVendor) ->               
   (FlatComputerList flatComputerList)
{
  // iterate over the vendors  
  for each (vendors = computerByVendor::Vendor) {
    // iterate over the OS's of the current vendor
    // requires accessing the current item of the 
    // outer iterator to define the items to iterate 
    // over for the inner iterator
    for each (OSs = iterator[vendors]::OS) {
      mapComputer 
       (oSName=iterator[OSs]::name,
        vendorName=iterator[vendors]::name) ->
        (computer=flatComputerList::computer);
}

mapComputer (String osName, String vendorName) -> 
            (Computer computer)
{
  copy(from=vendorName) -> (to=computer::vendor/name);
  copy(from=osName) -> (to=computer::OS/name);
}

Nesting Design

This section describes advanced nesting scenarios.

This section contains these topics:

Iteration within a Condition

This section describes mapping of multiple source members to a target based on a condition.

Example

If the total amount is more that $10,000 under the source invoice, then iterate over the line-items and increase the quantity by 1 for all line-items whose quantity is greater than 50, as shown in Figure 14-13.

Figure 14-13 Iteration without a Condition

Text description of ipusr091.gif follows

Text description of the illustration ipusr091.gif

Mapping Logic

The mapping requires a condition on the element total under the invoice element. Iterate over the line-item for all the instances where the total amount is greater that $10,000.

For all elements whose quantity is greater that 50, increment the line-item by 1 within each line-item.

If( inv::./line-item/total > 10000 )
  {
      int totalQuantity; 
  ...

  for each (lineItems = invoice::./line-item) {
     
     if( iterator line-items::quantity > 50 )
  
    { 
       add(first=iterator line-items::quantity, 
       second=1 -> result= variable totalQuantity);

    //copy the computed total quantity to the po quantity
  copy(from=variable totalQuantity -> 
      to=po::.item/quantity);
  }

  }

Condition within a Condition

A second condition is evaluated based on a value computed after the first condition evaluation.

Example

If street1 and street2 are not null under Address, (the first condition), concatenate these two strings. If the concatenated string's length is greater than 8, do a substring of length 8.

Figure 14-14 shows this scenario.

Figure 14-14 Condition within a Condition

Text description of ipusr092.gif follows

Text description of the illustration ipusr092.gif

Mapping Logic

This mapping requires a condition to verify that the values of street1 and street2 are not null. If the respective values are not null, concatenate street1 and street2. The inner condition must check for a length greater than 8 characters. A substring operation is performed if the concatenated string has a length greater than 8 characters.

if ( street1 != null  && street2 != null ) 

{
concatenetedStreet = concat ( street1 , street2 );
if (concatenetedStreet.size() > 8 ) 
{
resultStreet =  subString (concatenetedStreet ,8);
copy(from= resultStreet  ->  to=street);
}        
copy(from= concatenetedStreet  ->  to=street);
}

Although this example uses simple rules within the control flow constructs, domain value map and event header rules can also be used.

Transformation Map Variable Design

This section describes how to design advanced transformation map variable scenarios.

See Also:

Reuse (Preservation of State)

Map variables can also preserve the results of a computation, enabling it to be used in multiple places.

Example

A source Invoice has a Seller, Buyer, and Distributor, while a target PO has a Supplier, Purchaser, and Distributor. They map as shown in Table 14-2.

Table 14-2 Mapping
Invoice -> PO

Seller

->

Supplier

Buyer

->

Purchaser

Distributor

->

Distributor

All three sources in Invoice (Seller, Buyer, and Distributor) have an address that has street1 and street2, while the corresponding addresses in PO have only one field for street. An Invoice address is transformed to a PO address using concatString and other transformation maps.

The Distributor is usually the same as the Seller. In these cases, you can use map variables to perform the address computation once and use it in multiple places, as shown in "Mapping Logic":

Mapping Logic

The mapping logic is as follows:

copyInvoiceToPO (Invoice inv -> PO po)
{

// the map variable for the address
Address poSupplierAddr; 
concatString(firstString=inv::Seller::./address/street1, 
secondString=inv::Seller::./address/street2, resultString=variable 
poSupplierAddr::./street);
copyString(from=variable poSupplierAddr, to=po::Supplier::./address);
if (inv::Seller::./name = inv::Distributor::./name) {
   copyString(from=variable poSupplierAddr, to=po::Supplier::./address);
}
}

Event Header Rule Design

This section describes how to design advanced event header rules.

See Also:

"Event Header Rules"

Retrieving Contact/Identifier Information after Getting the Party

Retrieve the name of the from party using the event header rule getFromParty. Use the retrieved value to then retrieve the contact information of the party by using the transformation rule getPartyContactInformation.

Mapping Logic

This example retrieves the name of the from party from the event header into a map variable FromPartyNameMapVariable by invoking the event header rule getFromParty.

It then retrieves the party's Email by invoking the transformation map getPartyContactInformation. The global business identifier identified by the data universal numbering system (DUNS) number is also retrieved by invoking the transformation map getPartyContactInformation.

string FromPartyNameMapVariable;
     getFromParty (fromParty=FromPartyNameMapVariable);
getPartyContactInformation (partyName = FromPartyNameMapVariable, 
contactInfoType = 'Email' -> contactInfo = Ad_request/HR_Contact_Email); 
//Note: assuming  HR_Contact_Email to be next in //sequence after HR_Contact_
Name
getPartyContactInformation (partyName = FromPartyNameMapVariable, 
partyIdentificationType = 'Contact Name' -> partyIdentification = Ad_request/HR_
Contact_Name)

Domain Value Map Design

This section describes how to design advanced domain value maps.

See Also:

"Event Header Rules"

Multiple Party to Single Domain Relationship

In a domain value map, multiple parties can be associated with the same domain (column). A domain value map example is provided in the hiring process tutorial described in Chapter 7, "Tutorial of an Integration within an Enterprise". Assume you have many local newspapers and many global newspapers. Specifically, The Mercury and The Chronicle are of type Local Newspaper, and The Tribune and The Herald are of type Global Newspaper. Now suppose, the HR App, the local newspapers, and the global newspapers all have different terms for an advertisement. This is shown in Figure 14-15.

Figure 14-15 Domain-Party Relationship

Text description of ipusr093.gif follows

Text description of the illustration ipusr093.gif

Mapping Logic

To look up the common terminology given the description used by the HR App, you use the following:

HrAdToCommonView[EventTypeMap]  (AppEventType HR_Ad -> BusEventType Common_Ad)
{

lookupBusinessViewDomain (Party=HR_App, inValue=description -> 
outValue=description) in DVM AdTerminology;
}

See Also:

"Domain Value Map Rules"

Miscellaneous Designs

This section describes the mapping scenarios where the source and target structure have different levels of nesting of datatype members with multiple occurrences.

This section contains these topics:

Constructs with Anonymous Members

For nested choices or sequences, inner choices or sequences are modeled as anonymous members. Anonymous members cannot be mapped to any target as they are not present in the instance.

See Also:

"Creating a Complex Datatype" for conceptual details about the choice and sequence model groups

Constructs with Anonymous Members Example

The phone or e-mail are mapped under the choice member of the Ad_Request datatype. The choice member cannot be mapped to something else. In addition, any source member cannot be mapped to the target choice member.

Mapping Logic

The mapping logic is as follows:

copy(from=./[3]/phone -> to=./[3]/phone)

Figure 14-16 shows this scenario.

Figure 14-16 Constructs with Anonymous Members

Text description of ipusr089.gif follows

Text description of the illustration ipusr089.gif

Choice

A member of a datatype with a model group of choice must be checked for existence in the instance.

Example

The street1 and street2 datatype members are under the ADDRESS datatype whose model group is choice. Therefore, in the instance either street1 or street2 appear, but not both. Before copying street1 or street2 to the target, its existence can be checked in the instance.

if ( Exists ( street1 ) ) 
{

copy( from = street1 -> to = street1);
} else if (Exists ( street2) {
copy( from = street2 -> to = street2);
}

Referring to the Entire Map Parameter

Assume a datatype transformation map takes a complex datatype map parameter. This scenario describes a case where such a map invokes another submap with the entire complex datatype as a map parameter.

Example

When another submap is invoked with the same source or target parameter in a map, no path expression is required. Assume street is of multiple cardinality within the Addr complex datatype map parameter. You invoke a submap copyStreet that iterates over all the street members in the source and copies them to the target.

Mapping Logic

The mapping logic is as follows:

copyAddress(AppDatatatype Addr src -> AppDatatype Address target)
   {
   copyStreet(src=Addr   ->  target=Address);
   }

Multiple Datatype Members with the Same Name

There can be scenarios where more than one datatype member with the same name is present under a datatype (in the instance, they are known as siblings) and different transformation rules are defined for each. Although they appear under the same parent in the instance, Oracle Application Server ProcessConnect differentiates between them and executes only the rule defined for the respective member.

Multiple Members with the Same Name Example

The Address datatype's model group is sequence and it has two members with the same name of URL separated by another mandatory member (Name). These two members can have different transformation rules. Transformation can correctly determine the association during runtime.

Mapping Logic

The mapping logic is as follows:

copyAddresses[DatatypeMap](AppDatatype Addr src -> AppDatatype Address
target)
{

copyString(from=Address::./URL[1] -> to=Addr::./URL);
copyString(from=Address::./URL[2] -> to=Addr::./contact/URL);
}

Figure 14-17 shows this scenario.

Figure 14-17 Multiple Datatype Members with the Same Name

Text description of ipusr090.gif follows

Text description of the illustration ipusr090.gif

Chapter Summary

This chapter describes both troubleshooting and advanced topics in transformation design. Troubleshooting topics include common user errors (for example, not checking for the existence of an optional datatype member) and limitations on a transformation design (for example, only global map variables are supported). Advanced topics include how to design scenarios with iteration, nesting, and map variables (such as map variables that can preserve the results of a computation).


Go to previous page Go to next page
Oracle
Copyright © 2003 Oracle Corporation.

All Rights Reserved.
Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index