Exercise 4 (Optional). Validation Framework - Implementing A Named Constraint

What This Exercise Is About

Having learned how to use EMF's Validation Framework to validate model instance data, you will now add a named constraint to the XML Schema from which the model code was generated, and implement the validation code required to activate the constraint in your PurchaseOrder model editor.

Primer PO model


What You Should Be Able To Do

At the end of the lab, you should be able to:

Required Materials

General Advice / Warnings

Exercise Instructions

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

In your workspace, there should be a EMF_Workshop/Exercise4_Validation folder containing a new version of PurchaseOrder.xsd, which has been revised to include a named constraint.


Directions

Step A: Setup

  1. If you did not complete Exercise 1, please return to that exercise and complete it before proceeding.
  2. Switch to the Plug-in Development perspective, if not already there.
    1. Select Window -> Open Perspective -> Other... -> Plug-in Development.

Step B: Add Named Constraint to Schema

  1. Review the changes made to PurchaseOrder.xsd, compared to the version in the Exercise 1 source folder. If you open both the Exercise 1 and 4 source folders, you can select both versions of the file, then right-click and select Compare With -> Each Other. The following annotation was added.
  2.   <xsd:annotation>
        <xsd:appinfo source="http://www.eclipse.org/emf/2002/Ecore" 
          ecore:key="constraints">VolumeDiscount</xsd:appinfo>
      </xsd:annotation>

  3. Copy the Exercise 4 version of PurchaseOrder.xsd on top of the Exercise 1 version, replacing it. If you want to maintain two different files (for comparison), rename the Exercise 1 version first, then copy the Exercise 4 version into that folder.
  4. Open the file com.example.po/src/com.example.po.util/POValidator.java. This file contains methods used to validate your model. Using the Outline view, find the method validatePurchaseOrder(). Notice that it contains only one line, delegating this method to validate_EveryDefaultConstraint():
  5.   public boolean validatePurchaseOrder(PurchaseOrder purchaseOrder, 
        DiagnosticChain diagnostics, Map context)
      {
        return validate_EveryDefaultConstraint(purchaseOrder, diagnostics, 
          context);
      }

  6. Right-click the file com.example.po/model/PurchaseOrder.genmodel, and select Reload... in order to push changes to your schema into your generator model.
  7. Select XML Schema. Hit Next, then Next, then Finish.
  8. Open PurchaseOrder.genmodel (if not already open). Right-click the main node PurchaseOrder, then select Generate Model Code to regenerate your code from the new generator model.
  9. Switch back to POValidator.java. Notice now that the validatePurchaseOrder() method contains several more validation steps, and that there is also a new method, validatePurchaseOrder_VolumeDiscount(). This is the method we now must implement.

Step C: Implement Validation Code

  1. If you switch to the Tasks view (Window -> Show View -> Tasks), you will see a new TODO.
  2. TODO: implement the constraint validatePurchaseOrder_VolumeDiscount() in POValidator.java

  3. If you double-click the TODO, it will open the associated file (if not already open) and jump to the line containing the TODO comment.
  4. At this point, if you were to open your PurchaseOrder model editor (in your second workbench), you would not see anything different, since the constraint has not been implemented, and thus always returns true (valid).
  5. If pressed for time, you can copy code from the JPages folder under the Exercise 4 source folder. Otherwise, the steps to code are listed below.
  6. Ensure that you remove the @generated annotation or mark it @generated NOT, in order to prevent losing your changes should you regenerate.
  7. Iterate through the purchase order's items to compute the total value of the order.
  8.   float totalValue = 0;
      for (Iterator iter = purchaseOrder.getItems().iterator(); iter.hasNext(); )
      {
        Item item = (Item)iter.next();
        totalValue += item.getPrice() * item.getQuantity();
      }

  9. If the total value of the order is $500.00 or more, add a diagnostic with severity level Diagnostic.INFO. The method should always return true.
  10.   if (totalValue >= 500 && diagnostics != null)
      {
        diagnostics.add
          (new BasicDiagnostic
            (Diagnostic.INFO,
             DIAGNOSTIC_SOURCE,
             0,
             "This order qualifies for a 5% discount because its total value, $" 
               + totalValue + ", is at least $500.",
             new Object[] { purchaseOrder }));
      }
      return true;


Step D: Test Named Constraint

  1. Launch your second workbench again, using the same launch configuration from Exercise 1. There are many ways to do this.
  2. From your first workbench, copy the file Exercises/data/po-valid.xml into the po project of your second workbench. Rename the file to po-valid.po.
  3. Open the file po-valid.po. Select the Document Root node, then select PO Editor -> Validate. You will now get an information alert, since the value of the purchase order is at least $500. As in Exercise 1, this information will also appear in the Problems view.
  4. Validation Information: This order qualifies for a 5% discount because its total value, $649.0, is at least $500.

  5. Optionally, you may want to explore the other constraints in PurchaseOrder.xsd. If so, copy the other purchase order instance documents (*.po) in the EMF_Workshop/Solution4_Optional/data folder of your first workbench to your second workbench. Open each one in turn, validate it, and observe the errors that appear.

Summary

You have learned how to implement an arbitrary, named constraint in an XML Schema document, then generate the code to validate that constraint, and finally, to write the code to implement the details of the validation.


Sample Output

po-valid.po showing validation information (5% discount available)