EMF介绍系列(八、模型的验证)

在ecore模型里可以详细的定义各种类型、属性和方法,但对于像“每个类别里至少有两种产品”这样的限制就无能为力了。为此,EMF提供了一套验证框架(Validator Framework)用于解决这个问题,在ecore文件里特定的方法可以被识别为验证方法并生成用于验证的代码。

还是以shop模型为例,假设要求“每个类别里至少有两种产品”,我们需要在shop.ecore里添加一个名为validateProductsCount的验证方法,如图1所示。验证方法的返回类型是要具有两个参数:第一个是EDiagnosticChain类型,第二个是EMap类型,参数的名称没有特别要求,但这两个参数的顺序不能交换。

file
图1 新增的验证方法

接下来,通过shop.genmodel重新生成一遍代码(如果还没有shop.genmodel文件,通过New -> EMF Model创建一个),注意没有必要reload这个genmodel文件。通过比较添加验证方法前后的代码,可以发现EMF在util包里多生成了一个名为ShopValidator.java的文件;同时,在CategoryImpl的validateProductsCount()方法里的代码如下所示:

/**
 * <!-- begin-user-doc -->
 * <!-- end-user-doc -->
 * @generated
 */
public boolean validateProductsCount(DiagnosticChain diagnostics, Map contex) {
    // TODO: implement this method
    // -> specify the condition that violates the invariant
    // -> verify the details of the diagnostic, including severity and message
    // Ensure that you remove @generated or mark it @generated NOT
    if (false) {
        if (diagnostics != null) {
            diagnostics.add
                (new BasicDiagnostic
                    (Diagnostic.ERROR,
                     ShopValidator.DIAGNOSTIC_SOURCE,
                     ShopValidator.CATEGORY__VALIDATE_PRODUCTS_COUNT,
                     EcorePlugin.INSTANCE.getString("_UI_GenericInvariant_diagnostic", new Object[] { "validateProductsCount", EObjectValidator.getObjectLabel(this, contex) }),
                     new Object [] { this }));
        }
        return false;
    }
    return true;
}

有别于普通方法的实现(简单的抛出一个UnsupportedOperationException异常)。由于这段代码是被if(false){...}包围的,所以如果不进行定制,则里面的内容永远不会被执行,被包围代码的功能是将验证错误记录下来以便统一报告。现在,我们要做的就是修改这个条件,来告诉EMF什么时候运行里面的代码,如下所示:

/**
 * <!-- begin-user-doc -->
 * <!-- end-user-doc -->
 * @generated NOT
 */
public boolean validateProductsCount(DiagnosticChain diagnostics, Map contex) {
    // 我们修改了验证条件
    if (getProducts().size() < 2) {
        if (diagnostics != null) {
            diagnostics.add
                (new BasicDiagnostic
                    (Diagnostic.ERROR,
                     ShopValidator.DIAGNOSTIC_SOURCE,
                     ShopValidator.CATEGORY__VALIDATE_PRODUCTS_COUNT,
                     EcorePlugin.INSTANCE.getString("_UI_GenericInvariant_diagnostic", new Object[] { "validateProductsCount", EObjectValidator.getObjectLabel(this, contex) }),
                     new Object [] { this }));
        }
        return false;
    }
    return true;
}

因为我们要实现的验证条件很简单,所以代码的改动也很少,还是注意不要忘记修改注释中的@generated标记。现在可以运行我们的shop编辑器了,在一个只包含一种产品(Product)的类别(Category)上按右键,选择弹出菜单里的“Validate”命令,就会得到如图2所示的提示信息。

file
图2 模型未通过验证

通过修改代码的方式表达模型的限制条件是很直观,不过当条件又多又不确定的时候,直接在ecore文件里集中的表达这些条件也许更方便管理,而且Java代码甚至不需要重新生成和编译。Eclipse网站上的这篇文章“Implementing Model Integrity in EMF with EMFT OCL”通过自定义JET模板实现了这个功能,有兴趣的朋友不妨试试。

下载本文工程

补充另一种让EMF生成Validate代码的方法:在ecore模型里需要验证的EClass下建立一个EAnnotation,其source属性为“http://www.eclipse.org/emf/2002/Ecore”;然后在这个EAnnotation下建立key为“constraints”的Details Entry,value属性指定为想要的constraint名字,如果要定义多个constraint,则每个名字之间用空格分隔(格式见EcoreUtil#setConstraints()),如图3所示。这样,EMF就会在util包里生成XXXValidator.java文件,以及相应的验证方法,这些方法的代码和上面第一段嗲吗是类似的,同样需要自己修改if语句里的条件。

file
图3 在ecore模型里添加EAnnotation以生成验证代码

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2006/08/09/472607.html