Exercise 2: EMF Programming

Scenario

You will be building tools to work with purchase orders. Your company has existing shipping and billing systems that you need to integrate with. The basis for this integration will be an XML Schema for purchase orders, po.xsd, which is already used by the shipping system.

In this exercise, you'll implement a purchase order filling action that will be added to the generated editor. You will write code that processes purchase order data using the EMF runtime APIs, the APIs generated from the model, and the APIs for the existing shipping and billing systems.

Objectives

At the end of the exercise you should be able to:

Required Software

The screen captures in this document are based on Eclipse 3.4 M5 and EMF 2.4 M5.


Directions

This exercise is carried out entirely using the Eclipse Software Development Kit (SDK) with the Eclipse Modeling Framework (EMF) SDK installed into it. These instructions refer to this product as either Eclipse or the workbench.

This exercise builds on the three projects generated in Exercise 1. You will be working with two additional projects:

The full solution to this exercise is available in the Solutions folder. That folder contains the completed com.example.po.processing.ui project.

Part 1: Run the Fill Order Action

A stub FillOrderAction is provided in the com.example.po.processing.ui project. Although not fully implemented, it can already be run from the UI.

  1. Launch a new Eclipse workbench in debug mode.
  2. In the newly launched Eclipse workbench, open the instance document, supplier.po, created in Exercise 1.
  3. Run the Fill Order action.

When implemented, the Fill Order action will set the ship date of items as they are shipped. So, it considers an order already filled if this date is set on all of its items. If you are unable to run the action because of this, you can clear the ship date on items by selecting Ship Date in the Properties view and clicking on its Restore Default Value toolbar button. Or, you can just use the sample supplier.po file, which has no ship dates set initially.

Restore Default Value

Part 2: Implement the Fill Order Action

In the remainder of this exercise, you will implement the Fill Order action. You'll do your development in the first workbench and launch a second workbench in the debugger whenever you need to test it.

In the com.example.po.processing.ui project, expand the packages under the src folder and open FillOrderAction.java. Find the fillOrder() method. As you'll see, it's just a stub that throws an exception. Implement the method as follows:

  1. Create a new resource set, and a resource in it to use in serializing the purchase order. Make a deep copy of the selected purchase order, and use that copy in a new document root as the resource's contents.
  2. Save the resource to a StringWriter.
  3. Create a Shipper (recall that this a class from the com.example.po.processing plug-in) and prepare the order.
  4. If any unshipped items are ready to be shipped, accumulate a list of those items, calculate their total cost, and set their ship dates.
  5. Submit the credit card information and total cost to the Biller (also from com.example.po.processing).
  6. If the billing transaction is successful, ship the order and return the shipped items.
  7. Otherwise, if payment is refused, cancel the shipment and return null.
  8. Otherwise, if no items are ready, just return an empty list.

Shipper and Biller log messages to standard out, which appear in the Console view of the development workbench. Once the fillOrder() method is complete, the action should report results that match these messages.

However, there are still couple of improvements left to be made, which you'll do in the last two parts of the exercise.

Part 3: Add Validation

If you try to fill an invalid order (for example, with no order ID or no billing address), you'll see that the shipper refuses the order by throwing a Shipper.InvalidPurchaseOrderException from prepare(). This results in the display of the following dialog.

Invalid order

Clicking the Details button shows only the exception itself, which provides no detailed information about what is wrong with the order. It would be better to perform validation right in the action. Then, if any problems are found, the details of those problems can be shown to the user.

Add validation of the purchase order to the fillOrder() method as follows:

  1. After the selected purchase order has been copied and added to the resource, but before the resource is saved, invoke validation on the copy of the purchase order.
  2. If the resulting Diagnostic indicates an error, wrap it in a DiagnosticException and throw it.

The diagnostic is then extracted from the exception and used to describe the problems in the dialog. Notice that the resulting dialog looks just like the one displayed after running the Validate action in Exercise 1.

Part 4: Add Roll-back

After finding out from the shipper that items are available to be shipped, fillOrder() goes through those items and sets the ship date on each. Unfortunately, there is a problem with this approach: if the biller refuses payment, the items won't be shipped, but will already have had their ship dates set. You can solve this problem by recording the changes and rolling them back if billing is unsuccessful.

Add change recording and roll-back to the fillOrder() method as follows:

  1. After the shipper prepares the order, use a ChangeRecorder to record changes made to the purchase order while processing the items.
  2. End recording and obtain a ChangeDescription after processing the items.
  3. If billing is unsuccessful, apply() the changes to roll back the transaction.

Summary

You implemented an action that fills purchase orders, using generated model APIs and the persistence framework to manipulate and serialize EMF data. You then added validation to report any problems before attempting to process an order, and implemented roll-back to leave the data unchanged in case of an incomplete transaction.