# Tutorial: Designing a Purchase Order Processing System by Using AquaLogic Integrator

# Aggregating the Purchase Order Fulfillment Results

This chapter discusses the following topics:

- Publishing the PurchaseOrder Fulfillment Results to Message Broker Channels
- Designing the PurchaseOrderAggregator JPD to Subscribe to the Message Broker Channels
- Creating the Business Service Endpoint for PurchaseOrderAggregatorJPD

## Publishing the PurchaseOrder Fulfillment Results to Message Broker Channels

This section describes how to create decision-making nodes in the PurchaseOrderFulfillmentJPD that you created in the Designing PurchaseOrderFulfillmentJPD. Decision making nodes are included in the PurchaseOrderFulfillmentJPD to publish the fulfillment results to the message broker channels.

### Publishing the PO Fulfillment Results

##### Publishing Inventory System Results

1. Switch to Process perspective. From the BEA WorkSpace Studio menu, select Window > Open Perspective > Other..., and select Process from the Open Perspective dialog box.
2. In Package Explorer, expand alint.process.control, and drag and drop GenericPublishControl.java to Data Palette.
3. In the Source view, replace the variable name `genericPublishControl` with `publishPriceInfoControl`.
4. Add the following annotation before the variable:

    @com.bea.control.PublishControl.ClassPublish(channelName="/ALIntPOApp/OrderPriceInfo")

Note: | This PublishControl is used to publish the OrderPriceInfoDocument received from the external inventory system to the `/ALIntPOApp/OrderPriceInfo` channel. The `PurchaseOrderAggregatorJPD` will subscribe to the channel that receives the message.

Figure 7-1 shows the renamed variable, and the new annotation.

Figure 7-1 Annotation and New Variable

5. Go to the Source view, and add the following lines of code:

    public boolean isUpdateInventorySuccess() {

    		return priceInfo.getOrderPriceInfo().xgetRejectionCode() == null;

        	}

Note: | This method tests whether the inventory update is successful, by checking the rejection code in the OrderPriceInfoDocument received from the external inventory system.

6. From the Node Palette, drag and drop a Decision node to the Design view after the updateInventory node, and rename the Decision node as Check If Inventory Update is successful.
7. Right-click the Check If Inventory Update is successful node, and click Open. In the dialog box that is displayed, select the Java Method Name from the drop-down list, as shown in Figure 7-2.
Figure 7-2 Selecting Java Method Name

8. Drag and drop a Perform node into the Check If Inventory Update is successful node. Double-click the Perform node, and rename the method to `calcOrderPrice`. Click View Code, and type the following code:

    List<OrderLineItemPriceInfo> itemPriceList = priceInfo.getOrderPriceInfo().getOrderLineItemList();

    		Iterator<OrderLineItemPriceInfo> priceItr = itemPriceList.iterator();

    		while (priceItr.hasNext()) {

    			orderPrice += priceItr.next().getPrice();

    }

Note: | In case of compilation errors, ensure that the following imports are added to the code:

    import java.util.Iterator;

    import java.util.List;

    import org.openuri.purchaseOrder.OrderLineItemPriceInfo;

Note: | Figure 7-3 shows the code in Perform node.

Note: | The `calcOrderPrice` method calculates the total order price, which is used to transfer funds from the customer credit card.

Figure 7-3 Perform Node - Source View

9. Expand Controls > publishPriceInfoControl in the Data Palette. Drag and drop voidpublishWithMetadata into the Condition node in the Design view. Double-click the publishWithMetadata node. In the Send Data tab, select `OrderMetadata` and `priceInfo` from the Select variables to assign drop-down list. Figure 7-4 shows the variable options on the Send Data tab.
Figure 7-4 publishWithMetadata - Send Data Tab

10. Click Close.
11. From the Node Palette, drag and drop Perform node into the Decision Default node on the Design view. Rename the Perform node to `Throw Exception`, and rename the method to `throwEx`. Enter the following code in the Source view:

    TxHelper.getUserTransaction().setRollbackOnly();

    		String errorInfo = ccTranInfo.xgetErrorMessage().getStringValue();

    		throw new RuntimeException(ccTranInfo.xgetErrorMessage().getStringValue());

Note: | In case of compilation errors, ensure to add the following imports to the code:

    import weblogic.transaction.TxHelper;

You have now reviewed the response from the external inventory system and verified that the inventory update was successful, and no rejection code is set. When the inventory is updated, the OrderPriceInfo document is published to the /ALIntPOApp/OrderPriceInfo channel.

Figure 7-5 shows the process in Design view.

Figure 7-5 Inventory System

##### Publishing Credit Card System Results

1. In Package Explorer, expand alint.process.control, and drag and drop GenericPublishControl.java to Data Palette.
2. In the Source view, replace the variable name genericPublishControl with `ccTxInfoPublishControl`.
3. Add the following annotation before the variable names:

    @com.bea.control.PublishControl.ClassPublish(channelName = "/ALIntPOApp/OrderCCTransactionInfo")

Figure 7-6 shows both the new variable and the annotation.

Figure 7-6 Annotation and New Variable

4. Go to Source view, and add the following method:

    public boolean isMoneyTransferSuccess() {

    return ccTranInfo.xgetRejectionCode() == null;

    }

5. From the Node Palette, drag and drop a Decision node to the Design view after the transferMoney node. Rename this node to `Check If Money Transfer is Successful`.
6. Right-click on Check If Money Transfer is Successful, and select Open. From the Java Method Name drop-down list, select isMoneyTransferSuccess. Click Close.
7. Expand Controls > ccTxInfoPublishControl in the Data Palette. Drag and drop publishWithMetadata into the Condition node in the Design view. Double-click the publishWithMetadata node. In the Send Data tab, select `orderMetadata`, and `ccTranInfoDoc` from the Select variables to assign drop-down list. Figure 7-7 shows the variable options on the Send Data tab.
Figure 7-7 publishWithMetaData - General Settings Tab

8. Click Close.
9. From the Node Palette, drag and drop the Perform node into the Decision Default node on the Design view. Rename the method to `throwEx2`. Enter the following code in the Source view:

    TxHelper.getUserTransaction().setRollbackOnly();

    		String errorInfo = ccTranInfo.xgetErrorMessage().getStringValue();

    		throw new RuntimeException(ccTranInfo.xgetErrorMessage().getStringValue());

Figure 7-8 shows the exception code in the Source view.

Figure 7-8 Default Perform Node - Exception Code in Source View

You have now reviewed the response from the external credit card system and verified that the money transfer was successful and no rejection code is set. If the money transfer transaction is successful, the CreditCardTransactionInfo document is published to the /ALIntPOApp/CCTransInfochannel.

You have designed the PurchaseOrderFulfillmentJPD to invoke the external inventory and credit card systems, in the context of the JPD's implicit transaction. In case of an error, the transaction is rolled back, and an exception is thrown.

In the transaction succeeds, the results are published to respective message broker channels.

## Designing the PurchaseOrderAggregator JPD to Subscribe to the Message Broker Channels

The PurchaseOrderAggregatorJPD aggregates the results of the PurchaseOrderFulfillment JPD. This JPD dynamically subscribes to the message broker channels, to which the PurchaseOrderFulfillment JPD will publish the results of the inventory service and credit card service external systems.

This section describes how to design the PurchaseOrderAggregatorJPD to subscribe to the message broker channels and to aggregate the purchase order fulfillment results.

This section discusses the following tasks:

- To Design the PurchaseOrderAggregatorJPD
- To Add the Subscription Message Broker Channels to the JPD

##### To Design the PurchaseOrderAggregatorJPD

1. Create a PurchaseOrderAggregatorJPD. In the Package Explorer, right-click on alint.process, select New > Other > WebLogic Integration > Process. In the New Process dialog box, enter `PurchaseOrderAggregatorJPD` as the Name of the Process. Type `alint.process` as the Package, if the package is not already set.
2. Drag and drop Client Request from Node Palette to the Design view of PurchaseOrderAggregatorJPD, and double-click to rename it `AggregatePurchaseOrder`, as shown in Figure 7-9.
Figure 7-9 Client Request Node

3. Double-click on the AggregatePurchaseOrder node, enter `AggregatePurchaseOrder` in Method Name and click Add...
4. In the dialog box that is displayed, add the following variable names:

    java.lang.String orderId

    org.openuri.purchaseOrder.ShippingAddressDocument shippingAddress

    java.lang.String customerName

Table 7-1 lists the parameters and types of these variable names.

Table 7-1 Variable Names
Parameter Name | Type Name
orderId | `java.lang.String`
shippingAddress | `org.openuri.purchaseOrder.ShippingAddressDocument`
customerName | `java.lang.String`

5. Click Close. Figure 7-10 shows the parameters in the AggregatePurchaseOrder node.
Figure 7-10 AggregatePurchaseOrde Node - Parameter Values

6. Create the following instance variables in the Source view of PurchaseOrderAggregatorJPD:

    public java.lang.String customerName;

    public java.lang.String OrderId;

    public org.openuri.purchaseOrder.ShippingAddressDocument shippingAddr;

    public org.openuri.purchaseOrder.OrderPriceInfo priceInfo;

    public org.openuri.purchaseOrder.CCTransactionInfo ccTransactionInfo;

    public org.openuri.purchaseOrder.PurchaseOrderId purchaseOrderId;

    public org.openuri.purchaseOrder.ConsignmentInfo consignmentInfo;

    public org.openuri.purchaseOrder.PurchaseOrderStatusDocument status;

Figure 7-11 shows instance variables in Source view.

Figure 7-11 Instance Variables

7. Add the following annotation before the `AggregatePurchaseOrder` method name:

    @Protocol(jmsSoap = true, javaCall = true)

8. Edit the AggregatePurchaseOrder method, and assign the parameters as follows:

    this.orderId = orderId;

    this.shippingAddr = shippingAddress;

    this.customerName = customerName;

            // #END  : CODE GENERATED - PROTECTED SECTION - you can safely add code below this comment in this method. #//

    purchaseOrderId = org.openuri.purchaseOrder.PurchaseOrderId.Factory.newInstance();

            purchaseOrderId.setOrderId(this.orderId);

Figure 7-12 shows the code added in Source view.

Figure 7-12 Assigning Values to Variables

##### To Add the Subscription Message Broker Channels to the JPD

1. From Package Explorer, src > alint.process.control, drag and drop GenericSubscriptionControl to the Data Palette > Controls folder.
2. In the Source view, rename this control to `orderPriceSbscrptnn`.
3. Add the following annotation before the `orderPriceSbscrptnn` line in Source view.

    @com.bea.controls.SubscriptionControl.ClassSubscription(channelName = "/ALIntPOApp/OrderPriceInfo",

    xquery = "data($metadata)",

    xqueryVersion = com.bea.wli.common.XQuery.Version.v2004)

4. Drag and drop subscribeWithFilterValue from Data Palette > Controls > orderPriceSbscrptn after the AggregatePurchaseOrder node in the Design view.
5. Double-click the subscribeWithFilterValue node, click Send Data, and select `orderId` from the Select Variables to Assign drop-down list.
6. Drag and drop GenericSubscriptionControl from src > alint.process.control into the Data Palette. Rename this control to `ccTxInfoSbscrptnn` in Source view.
7. Add the following annotation before the `ccTxInfoSbscrptnn` line in Source view:

    @com.bea.controls.SubscriptionControl.ClassSubscription(channelName = "/ALIntPOApp/OrderCCTransactionInfo",

            xquery = "data($metadata)",

            xqueryVersion = com.bea.wli.common.XQuery.Version.v2004)

8. Drag and drop subscribeWithFilterValue from Data Palette > Controls > ccTxInfoSbscrptnn after the orderPriceSbscrptnn node. Rename this node as ccTxInfoSbscrptnn.
9. Double click the subscribeWithFilterValue node, click Send Data, and select `orderId` from the Select Variables to Assign drop-down list.

You have now designed the PurchaseOrderAggregatorJPD to subscribe to the message broker channels to which the results of the PurchaseOrderFulfillmentJPD are published.

##### Designing Parallel Branch in the JPD

1. From Node Palette, drag and drop a Parallel Branch after the ccTxInfoSbscrptnn in the Design view.
2. From the Data Palette > Controls > orderPriceSbscrptnn, drag and drop void onMessage(XmlObject message) into the first Parallel Branch.
3. Right-click on this node, and select View Code. Add the following code in the Source view:

    try

    {

    priceInfo = org.openuri.purchaseOrder.OrderPriceInfo.Factory.parse(message.xmlText());

    }

       catch (XmlException e) {

        throw new RuntimeException(e);

    }

4. Similarly, from the Data Palette > Controls > ccTxInfoSbscrptnn, drag and drop void onMessage(XmlObject message) into the first Parallel Branch.
5. Again, from the Data Palette > Controls > ccTxInfoSbscrptnn, drag and drop void onMessage(XmlObject message) into the second Parallel Branch.
6. Right-click on this node, and select View Code. Add the following code in the source:

    try {

             ccTransactionInfo = org.openuri.purchaseOrder.CCTransactionInfo.Factory.parse(message.xmlText());

    } catch (XmlException e) {

    throw new RuntimeException(e);

    }

Note: | You have now designed the PurchaseOrderAggregatorJPD to aggregate the results from the message broker channels.

##### Invoking the External Shipping System

1. From the Package Explorer, drag and drop ServiceProviderAccessControl.java into Data Palette.

Note: | ServiceProviderAccessControl is the ALSB Control that you created in Creating AquaLogic Service Bus Control.

2. Drag and drop XmlObject accessService(String ServiceName_arg,XMLObject_Any_arg) from ServiceProviderAccessControl after the second Parallel Branch in the Design view. This is the accessService node.
3. Add the following code in the Source view of the method:

    this.consignmentInfo = org.openuri.purchaseOrder.ConsignmentInfo.Factory.parse(serviceProviderAccessControl.accessService(“ShippingService”, this.purchaseOrderId).xmlText());

Figure 7-13 shows the code you have just added.

Figure 7-13 Code for the AccessService Method

4. Drag and drop a Perform node from the Node Palette after the accessService node.
5. Double-click the Perform node, and type `archiveOrder` in JavaMethodName.
6. Right-click the Perform node, click View Code, and replace public void archiveOrder() throws Exception { with the following code:

    public void archiveOrder() throws Exception {

                            File orderFile = new File("C:/ALIntApp/PurchaseOrder/New/PO-" + orderId + ".xml");

                            orderFile.renameTo(new File("C:/ALIntApp/PurchaseOrder/Archive/PO-" + orderId + ".xml"));

        }

After you have added the Perform node, you must unsubscribe from the subscriptions.

##### Unsubscribing from the Message Broker Channels

1. Drag and drop void unsubscribe() from Data Palette > Controls > ccTxSbscrptnn under the Perform node.
2. Similarly, drag and drop void unsubscribe() from Data Palette > Controls > orderPriceSbscrptnn under the Perform node.

In the next step, you send the Purchase Order status as a callback.

##### Sending Order Status as Callback

1. Drag and drop a Client Response node from the Node Palette to the Design view.
2. Double-click the Client Response node, and rename the Method Name to `AggregatePurchaseOrderStatus`.
3. Click Add to add the `PurchaseOrderStatusDocument x0`, as shown in Figure 7-14.
Figure 7-14 Adding Variable in the Client Response Node
4. Right-click on the Client Response node, and select View Code. Add the following in Source view.

    status = org.openuri.purchaseOrder.PurchaseOrderStatusDocument.Factory.newInstance();

            org.openuri.purchaseOrder.PurchaseOrderStatusDocument.PurchaseOrderStatus s = status.addNewPurchaseOrderStatus();

            org.openuri.purchaseOrder.PurchaseOrderId poID = s.addNewPurchaseOrderId();

            poID.setOrderId(this.orderId);

            s.setConsignmentInfo(this.consignmentInfo);

            s.setOrderLineItemInfo(this.priceInfo);

            s.setCCTransactionInfo(this.ccTransactionInfo);

            s.setCustomerName(this.customerName);

            // #START: CODE GENERATED - PROTECTED SECTION - you can safely add code above this comment in this method. #//

            // input transform

            // method call

            callback.AggregatePurchaseOrderStatus(this.status);

            // output transform

            // output assignments

            // #END  : CODE GENERATED - PROTECTED SECTION - you can safely add code below this comment in this method. #//

Figure 7-15 shows the Source view.

Figure 7-15 Client Response Method in PO Aggregator JPD

1. In Source view, add the following annotation before this method name:

    @Protocol(jmsSoap = true, javaCall = true)

Figure 7-16 shows the Purchase Order Aggregator JPD in Design view.

Figure 7-16 PurchaseOrderAggregatorJPD

## Creating the Business Service Endpoint for PurchaseOrderAggregatorJPD

The business service end points are used by ALSB proxy services to invoke the Purchase Order Aggregator JPD for aggregating the purchase order results.

##### To Create the Business Service Endpoint

1. Switch to the ALSB perspective from your current perspective in BEA WorkSpace Studio. To select the ALSB perspective, in the BEA WorkSpace Studio window menu, click Windows > Open Perspective > Other....

Select AquaLogic Service Bus from the Open Perspective dialog box.

2. In the Project Explorer pane, select ServiceAccess > Business Services > New.
3. In the Create a new Business Service dialog box, enter the File Name as `PurchaseOrderAggregatorJPDBS`, and click Next.
Figure 7-17 Create a Business Service

4. In the Create Business Service - General Configuration (Service Access/Business Services/) dialog box, select WSDL Web Service Service Type, and click Browse. The Select a WSDL dialog box is displayed.
5. Select Service Access, and click Consume. In the Service Consumption dialog box, browse to ServiceAccess > Resources, and select `ServiceAccess\Resources` as the Artifact folder.
6. From the Service Resource drop-down list, select Workspace.
7. Browse to \UseCaseWeb\src\alint\process\, select PurchaseOrderAggregatorJPDContract.wsdl, and click OK.
8. Click OK in the Service Consumption Status dialog box.
9. In the Select a WSDL dialog box, expand Resources, select and expand `PurchaseOrderAggregatorJPDContract.wsdl`, and then select PurchaseOrderAggregatorJPDSoap(port), click OK, as shown in Figure 7-18.
Figure 7-18 Select a WSDL

10. Click Next in the Create a Business Service - Transport Configuration (ServiceAccess/Business Services) dialog box, and ensure the following:

- The Protocol is set to jpd.
- The Endpoint URI is: `jpd::/UseCaseWeb/alint/process/PurchaseOrderAggregatorJPD.jpd`. Click Add. and click Next. Figure 7-19 shows the default values selected.
Figure 7-19 Selecting Protocol and Endpoint URIs

11. In the JPD Transport Configuration dialog box, accept the default values, and click Finish.

The `PurchaseOrderAggregatorJPDBS.biz` file is created in the Business Services folder in Project Explorer. In PurchaseOrderAggregatorJPDBS.biz, click the JPD tab. Ensure that the Callback Proxy Location is `jms://localhost:7001/weblogic.jms.XAConnectionFactory/PurchaseOrderNotificationServiceRequest`.

Notes: | Callbacks are only supported over JMS when JPD transport is used. Therefore, you must configure it over JMS.

Note: | While configuring the JPD transport for invoking JPD as a business service, you must specify the location to the callback proxy, which is configured for JMS (in callback pipeline). WLI sends the callback response to the queue on which callback proxy is configured (in callback pipeline). Along with the response, WLI also sends the original callback location, which is part of the original request, as a JMS transport header. You can configure the callback pipeline so that the callback is sent to this callback location.

Note: | The original callback location is sent as a JMS property namely `BEA_WLI_Target_Callback_Location`. If the original callback location contains any additional query strings, those query strings are also be sent as JMS transport headers. You must retrieve this property from the message context variable `$inbound`, and this can be used to configure the outgoing business service for sending the callback, to the actual JPD callback client.