Model Validation

The following example demonstrates how to validate a model exported by your CASE tool. You can find the templates and the model for this example at: ../samples/getting_started/validation. The templates use the Model Validation feature and will generate an HTML report for the underlying UML model.

Here is a complete list of files of this example:

Table 2.5. Files for the Model Validation example

DirectoryFileComment
./validation.iqpProject file for this example
./build.xmlAnt Script for generation
modelvalid_model.xmiValid model XMI file
modelinvalid_model.xmiInvalid model XMI file
modelmodel.zargoArgoUML model file
templatesmain.jspModel element to template mapping, Validation
templatesreport.jspCreates the HTML output

UML Profile

The UML profile in this case is very simple. What we want to show is how to use model validation. Model validation answers the question: Does the UML model satisfy the UML profile?

The UML profile looks like this:

  • only Entity, Process and Enum are allowed stereotypes

  • every navigable association must be named with a rolename

  • a usage dependency of processes to classes shows implicitly a get method of the used class

This is very simple but it will suffice for our needs.

Model

First let us start with the invalid model. It looks as follows:

Figure 2.4. Invalid model

Invalid model

You can find the invalid model as XMI file in the folder validation/model. Please open the transformation samples/getting_started/validation/validation.iqp. When you start generation and change to the validation page you should see that the model has three validation errors:

Unknown stereotype:Class: User
Association [Document -> Version] is navigable but missing rolename.Association:
Association [Version -> Label] is navigable but missing rolename.Association:

The Unknown stereotype error is a warning, the missing rolename exceptions are errors (different images in table!). If we used a fatal error the execution would have stopped. In our example the validation violation status are arbitrarily.

The next step is that we fix the model, remove the validation violations and re-generate. The correct model looks as follows:

Figure 2.5. Valid model

Valid model

You can load the model from the XMI file valid_model.xmi. Now re-generating will not produce errors anymore!

Templates

You can find both templates main.jsp and report.jsp in the templates directory of this example. Most of the used methods are explained in further examples so we can concentrate on the validation method (see main.jsp):

[...]
private static final List STEREOTYPES = Arrays.asList(
   new String[] {"Entity", "Process", "Enum"}
);
[...]
public boolean canBeGenerated(MBase pElement) {
   return super.canBeGenerated(pElement)
      || getMetaModel().isAssociation(pElement);
}

public ValidationMessage isValid(MBase pElement) {
   String s = getMetaModel().getStereotype(pElement);
   // valid stereotypes
   if (getMetaModel().isClass(pElement) && !STEREOTYPES.contains(s)) {
      return new ValidationMessage(ValidationMessage.WARN, "Unknown stereotype: " + s);
   }
   // navigable associations do have a rolename?
   if (getMetaModel().isAssociation(pElement)) {
      for (Iterator it = ((MAssociation)pElement).getConnections().iterator(); it.hasNext(); ) {
         MAssociationEnd lAssocEnd = (MAssociationEnd)getMetaModel().getOppositeEnd((MBase)it.next());
         if (getMetaModel().isNavigable(lAssocEnd)
               && getMetaModel().getName(lAssocEnd).length() == 0) {
            StringBuffer sb = new StringBuffer();
            sb.append("Association [");
            sb.append(getMetaModel().getTypeName(lAssocEnd.getOppositeEnd()));
            sb.append(" -> ");
            sb.append(getMetaModel().getTypeName(lAssocEnd));
            sb.append("] is navigable but lacks a rolename.");
            return new ValidationMessage(ValidationMessage.ERROR, sb.toString());
         }
      }
   }
   return new ValidationMessage(ValidationMessage.OK, "No error found!");
}
[...]                

The model validation happens programmatically. For validation purpose you can use the hook method isValid. This method is called for every model element that is to be processed during generation. You can control which model element leads to the generation of an artifact by overwriting the method canBeGenerated. By default only classes and interfaces are generated. In our example we have added associations, because the UML profile demands a validation of associations, too. Our intention is to check navigable associations and their rolenames.

In our custom isValid method we check whether all classes have a valid stereotype - if not we return a ValidationMessage of type ValidationMessage.WARN. Then we check whether all navigable associations have rolenames.

To do this we check, if the element is an association, then we take a look at the association's ends. Every association consists of two association ends which you can get by calling the method getConnections. Finally we check the UML profile constraint ("Association is navigable and has a rolename?!?"). If this constraint is violated we return a ValidationMessage of type ValidationMessage.ERROR.

If the element is no association in the first place, there is nothing to test form, so we simply return a ValidationMessage of type ValidationMessage.OK.

Tip

In a real world application the model validation would be more complex. Therefore we recommend to handle it in a separate class. Our experience is that it is also an incremental process to make your model validation more and more detailed. In a way, this is comparable with unit testing your model.