内容


使用 Rational Software Architect 中的拓扑编辑器来添加一个定制确认器

定制技术域的确认机制选项

Comments
下载 Rational® Software Architect 试用版  |  在线试用 Rational® System Architect
下载更多的 IBM 软件试用版,并加入 IBM 软件下载与技术交流群组,参与在线交流。

确认器是如何查找拓扑问题的

本文是对以前所发表的一篇名为 使用定制技术领域扩展拓扑 IBM Rational Software Architect 拓扑编辑器文章的扩充。它解释了怎样使用代表 MySQL 系统的拓扑单元与功能来创建一个定制 MySQL 域。本文还向您展示了怎样向该域添加定制确认器。

确认器 确保一个拓扑呈现了一个有效的部署场景,并帮助您识别部署过程场景早期中的问题。拓扑编辑器包含了一系列的确认器,去不断搜索拓扑中存在的问题。例如,一个默认的确认器会确保带有安装需求的每个单元拥有对适当单元的安装连接(见于图 1)

图 1. 安装错误的屏幕截图
错误:带有丢失安装连接的 Tomcat 单元
错误:带有丢失安装连接的 Tomcat 单元

但是,拓扑编辑器域的变化本质意味着个人单元类型可以按照个性的方式运行。您可以为定制域创建确认器,以确保这些域中的单元和其他拓扑元素得到了适当的运用。

定制确认器可以检查不同范围内的问题:

  • Attribute 确认器会证实单个的属性会设置为一个有效的值,长度,格式,或者数据类型。例如,本文向您展示了一个确认器是如何确认版本号属性是否匹配版本号格式的,例如 4.0.2 或者 5.26.0。
  • Unit 确认器会确认单个的单元是有效的。单元确认器会检查单元上的功能,需求,属性以及链接,以确保单元会作为一个整体进行配置。
  • Domain 确认器会确认拓扑中两个或者更多个单元之间的关系。例如,域确认器可以确认拓扑中没有复制的值,例如端口号或者网络地址。域确认器还可以支持低级的确认器,例如单元确认器。
  • Constraint 确认器,它确认了模型元素的关系与特征,它超出了本文的讨论范围。

当您在一个拓扑之中发现一个确认器时,它可以向拓扑中的元素添加一个或者更多的错误,警告,或者信息(确认器还可以提供改正错误的解决方案,但是这也不在本文的讨论范围之列)。

前提条件

我们将会继续学习前一篇文章中的 MySQL 范例,学习怎样创建技术域。如果您已经在运行该范例,您就可以直接跳过该节,并继续学习下一部分。对于其他的读者来说,接下来的是运行 MySQL 域的“前期课程”。

导入定制 MySQL 域

  1. 安装 Topology Domain Generation Toolkit:
    1. 从本文的 参考资料 部分中下载 Topology Domain Generation Toolkit。
    2. 得到压缩的文件,然后从 ZephyrSDK 文件夹中得到 ZephyrSDK.zip 文件。
    3. 打开 IBM® Rational® Software Architect。选择 Help > Software Updates,并在向导的 Available Software 项中点击 Add Site
    4. 选择 Local 并切换至获得档案的目录。
    5. 点击 OK 并从 Available Software 对话框的新更新站点中选择 Domain Generation Feature
    6. 点击 Install 并按照随后的安装程序操作。
  2. 从本文的 下载 部分中下载 mysql.xsd 文件。
  3. 在 Rational Software Architect 之中创建一个新的项目:
    1. 选择 File > New > Project | General > Project,然后点击 Next.
    2. 在“Project name”区域中输入 org.example.mysql 并点击 Finish
  4. 在 Package Explorer 视图之中,右击 org.example.mysql 项目以向新项目添加一个文件夹,选择 New > Folder,并指定 model 作为名字。
  5. 在“model”文件夹之下添加两个文件夹,并将它们命名为 ecoreschema。
  6. 将操作系统上的文件复制到项目的工作区域中,来将下载的 mysql.xsd 文件导入到方案文件夹之中。在 Package Explorer 中,点击 F5 以查看项目之中的文件。

项目结构如图 2 所示。

图 2. MySQL 技术域扩展的初始项目结构
项目结构的 Package Explorer 视图
  1. 从 XSD 文件中创建 ecore 和 genmodel 文件:
    1. 在项目中右击 mysql.xsd 文件,并从内容菜单之中点击 New > Other
    2. 在向导中选择 Eclipse Modeling Framework > EMF Model,然后点击 Next
    3. 为 genmodel 文件选择 ecore 目录,然后点击 Next
    4. 选择 XML Schema 作为 Model Importer,并再次点击 Next
    5. 点击 Load 以激活 mysql.xsd 文件,然后点击 Next
    6. 在向导接下来的页面上部区域,选择 org.example.mysql,并在该对话框的下部选择所有的包。
    7. 然后点击 Finish

如果一切顺利,那么在项目的 ecore 文件中就会生成 mysql.ecore 与 mysql.genmodel 文件了。

注意: 如果在新对话框窗口中没有叫做 Eclipse Modeling Framework 的文件夹,那么您可以激活 Show all Wizards 复选框。

  1. 为 MySQL 域生成源代码:
    1. 在 Project Explorer 视图中双击以打开 mysql.genmodel
    2. 点击根元素并打开 Properties 视图(如图 3 所示)。
    3. 在 Properties 视图之中,将 Compliance Level 属性设置为 1.4(如图 3 的项目 1 所示),并将 Non-NLS Markers 属性设置为 true(项目 2)。
    4. 然后,在 Edit Directory 属性值中,删除 .edit,这样它就会被设置成 /org.example.mysql/src (item 3)
    5. 将所作的更改保存到 .genmodel 文件(Ctrl+s)之中。
    6. 再一次选择 .genmodel 文件的根元素并打开下拉菜单。
    7. 从下拉菜单之中,点击 Generate Model Code,然后点击 Generate Edit Code,最后,点击菜单 Generate Topology Edit Code

生成了两个插件:

  • 模型插件,包含了模型与编辑模式
  • 插件 org.example.mysql.ui,包含了图表视图的代码
图 3. 编辑 genmodel 属性
MySQL 根元素的 genmodel - 属性
MySQL 根元素的 genmodel - 属性

测试域

  1. 在运行时环境中测试域:
    1. 从模型或者 UI 项目 之中打开 plugin.xml 文件,并在 Overview 项的 Testing 部分中点击 Launch an Eclipse application 链接以启动 Rational Software Architect 的运行时实例。
    2. 在运行时实例之中,添加一个新项目(File > New > Project | General > Project)并将其命名为 org.example.mysql.topology
    3. 然后,向项目添加一个拓扑(右击 Project Explorer New > Topology 中的新项目)并给其起一个名字。
    4. 从 Palette 的 Middleware 折叠项之中,向拓扑添加一个 MySQLDatabaseSystemUnit。
    5. 在测试域扩展之后关闭运行时实例。

确认器 API 的元素

在生成 Topology Edit 代码时,Topology Domain Generation Toolkit 会为技术域生成单个的 域确认器 类,为域中所定义的每一个单元生成一个 单元确认器 类。

一个 域确认器 包含了证实该单元在拓扑中适当应用的逻辑。域确认器创建了对于一个域的单元确认器的实例,它证实了域中的个人单元,稍后将会讨论这一点。域确认器还包含了整个域的全局确认逻辑。例如,它可能还包含了适用于域中的每个单元,适用于相互联系的多个单元。域确认器可能还包含了规则去确保一些值,例如端口号,主机名以及 IP 地址在一个拓扑结构中是独一无二的。

一个 单元确认器 包含了确认单个类型单元的逻辑,它被分解为 功能属性 确认器。例如,单元确认器可以证实功能属性被设置为有效值,并以对该种单元适当的方式与其他单元相联系。您还可以在拥有特定功能,需求或者属性的单元确认器中添加逻辑。

您可以使用这些确认器来扩展拓扑中所提供的核心确认器规则。默认的核心确认器确保满足了基本的拓扑规则,例如拥有安装需求的单元有一个安装链接。向域与单元确认器添加您自己的逻辑,以创建特定于域的规则。

通过 Topology Domain Generation Toolkit 所生成的确认器基底包是 namespace.internal.validator。结果,对于 MySQL 域来说,如图 4 所示,在 org.example.mysql.internal.validator 包中有一个域确认器(MysqlDomainValidator)以及一个单元确认器(MySQLDatabaseSystemUnitValidator)。

图 4. 带有生成确认器类的 Package Explorer
显示模型项目类结构
显示模型项目类结构

在您开始实施一个定制确认器之前,您可以先查看一下在模型项目之中是如何定义结构的。

  1. 打开模型项目的 plugin.xml 文件(org.example.mysql)并点击 Extensions项。
  2. 打开 com.ibm.ccl.soa.deploy.core.domains 扩展以及标有“Mysql domain”的条目。在 Mysql 域节点之下,您可以找到如图 5 所示的域确认器条目。它只拥有一个指定确认器类的属性,确认请求将会自动调用它。
图 5. plugin.xml 文件之中的确认器声明
扩展项,选择的确认器条目
扩展项,选择的确认器条目

图 5 的大图

  1. 为了查看域确认器的细节信息,您可以打开 MysqlDomainValidator 类并点击 F4 以打开类的 Hierarchy Explorer(见于图 6)。

域确认器所指定的类必须直接或间接地扩展抽象的 DomainValidator 类,以让确认器框架适当地使用它。在这里的范例之中,生成的域确认器,MysqlDomainValidator,扩展了 UnitDomainValidator,而它本身又扩展了 DomainValidator。为了注册一个新的单一确认器,必须要调用 addValidator(…) 方法。如果 UnitDomainValidator 类的 validate(…) 方法得到了调用,那么所有注册单元确认器也会等到调用,而单元也会等到确认。

图 6. DomainValidator 的类层级结构
类型层级结构视图,UnitDomainValidator
类型层级结构视图,UnitDomainValidator

查看一下 MysqlDomainValidator 所生成的源代码(见于代码清单 1)。构造器方法会使用 MySQL 域包来初始化它的超类。这将会通知该包所声明的确认框架应该由域确认器来确认。然后,调用内部 addDomainValidators() 方法。在方法内部,所有单元确认器都会得到初始化和注册,以包含在域确认器之中(这里是 MySQLDatabaseSystemUnitValidator)。

清单 1. MysqlDomainValidator 所生成的源代码
...
publicclass MysqlDomainValidator extends UnitDomainValidator {

   /**
    * Construct a {@link MysqlPackage} domain validator.
    * 
    * @generated (domain-generator)
    */
   public MysqlDomainValidator() {
      super(MysqlPackage.eINSTANCE);
      addDomainValidators();
 }

   /**
    * Add domain validators as needed.
    * 
    * @generated (domain-generator)
    */
   protected void addDomainValidators() {
      addValidator(new MySQLDatabaseSystemUnitValidator());
   }

...

}

切换至单元确认器,并查看一下如代码清单 2 所示的 MySQLDatabaseSystemUnitValidator 源代码。该类来自于 UnitValidator,它作为所有单元确认器的超类,并包含了添加更多特定确认器类的方法,例如功能,属性,以及链接确认器。MySQLDatabaseSystemUnitValidator 包含了两个构造器方法,就是 addUnitTypeConstraints(…) 方法以及 validateUnit(…) 方法。方法 addUnitTypeConstraints(...) 是从构造器中调用的,它是确认器初始化单元内容的地方,例如单元可以包含的功能与需求的类型。

清单 2. MySQLDatabaseSystemUnitValidator 所生成的源代码
...
publicclass MySQLDatabaseSystemUnitValidator extends UnitValidator{

   public MySQLDatabaseSystemUnitValidator() {
      this(MysqlPackage.eINSTANCE.getMySQLDatabaseSystemUnit());
   }
...
   protected MySQLDatabaseSystemUnitValidator(EClass unitType) {
      super(unitType);
      assert MysqlPackage.eINSTANCE.getMySQLDatabaseSystemUnit().isSuperTypeOf(unitType);
      addUnitTypeConstraints();
   }
...
   protectedvoid addUnitTypeConstraints() {
      addCapabilityTypeConstraint(
         MysqlPackage.eINSTANCE.getMySQLDatabaseSystem(),
         CapabilityLinkTypes.ANY_LITERAL, 1, 1);
   }
...
   @Override
   publicvoid validateUnit(Unit unit, 
    IDeployValidationContext context, 
     IDeployReporter reporter) {
      super.validateUnit(unit, context, reporter);
   }
}

方法 validateUnit(…) 优越级高于来自 UnitValidator 的 validateUnit(…) 方法,并在确认一个单元实例时得到调用。这是单元确认器的首个进入点。注意避免因为频繁调用而使该方法产生不实际的逻辑。在接下来的部分中,我们将会添加一个检查 MySQL 版本属性的单元确认器。然后我们将会显示确认器错误是怎样在图表层次上报告的。

添加一个简单的单元确认器方法

MySQLDatabaseSystem 功能拥有一个名为“MySQLVersion”的属性,其属性为 xsd:string。因此,拓扑编辑器中的默认确认器会自动确保属性有一个字符串类型的值。在这里的范例之中,我们想要进一步地确保版本字符串符合号码与点的典型结构(例如:4.04,2.0.18,5.23.42)。

更新单元确认器类

在这一部分之中,您要更新单元确认器类,以将 MySQLVersion 属性与规范的表达式相比较。如果属性与版本号格式不相匹配,那么确认器会对该单元应用信息。范例向您提供了一个快速概述,告诉您单元确认器是如何工作,以及您需要什么步骤来向图表添加一条信息。该范例只用于演示。如有需要,它只能通过 DeployAttributeValidator 来实现。本文稍后将会介绍 DeployAttributeValidators。

首先您要做的是,向 org.example.mysql 插件的插件附件添加 org.eclipse.core.resources 包。该包包含了来自 Eclipse 平台的基本确认与错误报告机制。在拓扑编辑器的确认框架中将会使用到它们。

  1. 在 Plug-in Manifest 编辑器中打开 plugin.xml 文件,并选择 Dependencies 项。
  2. Required Plug-ins 区域之中,选择 Add 并在文本区域之中输入 org.eclipse.core.resources,选择对话框中的包并点击 OK
  3. 保存 您对 plugin.xml 文件所作的更改。

在下一步中,您将会编辑 MySQLDatabaseSystemUnitValidator 类的 validateUnit(…) 方法,当您在确认单元时将会调用该方法。validateUnit(…) 方法会得到以下的输入参数:

Unit unit
这是当前所确认的对象。该对象允许您去访问属性的当前值,以及对其他对象的连接。

IDeployValidationContext context
这是确认的扩展系统环境。

IDeployReporter reporter
该界面允许您向编辑器添加状态信息。

  1. 使用来自代码清单 3 的方法来替换 MySQLDatabaseSystemUnitValidator 类中已存在的 validateUnit(…) 方法,并添加全局变量 MYSQL_DB_VERSION_VALIDATOR_ID。
  2. 点击 Ctrl+Shift+o 以添加错误导入声明,并修复源代码之中的错误。
  3. 为了确定您的源代码没有被新的生成器运行所覆盖,您可以删除 validateUnit(…) 方法的 @generated 注释。
清单 3. 向 MySQLDatabaseSystemUnitValidator 类添加首个确认器
...
publicstatic final String MYSQL_DB_VERSION_VALIDATOR_ID =
      "MYSQL_DB_VERSION_VALIDATOR_ID";
...

publicvoid validateUnit(Unit unit, IDeployValidationContext context,
     IDeployReporter reporter) {
   super.validateUnit(unit, context, reporter);
   // get the MySQLDatabaseSystem capability from the current unit
   MySQLDatabaseSystem mysqlDBSystem = 
      (MySQLDatabaseSystem)ValidatorUtils.getCapability(unit,
           MysqlPackage.eINSTANCE.getMySQLDatabaseSystem());
   String version = mysqlDBSystem.getMySQLVersion();
   // check the version string against the regular expression
   if (version != null && !Pattern.matches("([0-9]+\\.)+[0-9]+", version)) {
      // if the version check fails,
      // create a new deploy status object with a status message
      IDeployStatus status = 
          DeployCoreStatusFactory.INSTANCE.createDeployStatus(
             IStatus.INFO,
             MySQLDatabaseSystemUnitValidator.MYSQL_DB_VERSION_VALIDATOR_ID,
             "InvalidVersionNumber",
             "Version number \"{0}\" does not match X.Y.Z",
             new Object[]{version},
             unit);
      // add the new status to the reporter
      reporter.addStatus(status);
   }
}

确认器类中的新 validateUnit 方法会执行以下操作,以决定单元是否有效,并报告单元所具有的问题:

  1. 确认器在其超类中调用 validateUnit 方法(...):super.validateUnit(unit, context, reporter);
    父类确认器所报告的确认器错误会随着该确认器所发现的错误一起积累。
  2. 它会从 ValidatorUtils.getCapability.MySQLDatabaseSystem mysqlDBSystem =
    (MySQLDatabaseSystem)ValidatorUtils.getCapability(
    unit,MysqlPackage.eINSTANCE.getMySQLDatabaseSystem());
    的单元中获得 MySQLDatabaseSystem 功能
  3. 它获取了字符串格式的版本属性。
    String version = mysqlDBSystem.getMySQLVersion();
  4. if 语句中,版本字符串首先会检查是否是 null(version != null)。如果不是 null,那么规范的表达式(Pattern.matches("([0-9]+\\.)+[0-9]+", version)) 评价了字符串是否与预定义的模式相匹配。
  5. 如果模式与版本字符串模式不相匹配,那么就会创建一条状态信息:
    DeployCoreStatusFactory.INSTANCE.createDeployStatus(…)
  6. 确认的最后一步是向报告器添加新的状态信息,它向编辑器添加了信息:
    reporter.addStatus(status);

在步骤 5 之中,我们会使用 DeployCoreStatusFactory 类,该类包含了有用的方法来创建不同类型的状态对象(在这里的案例中,就是一个 IDeployStatus)。我们会向 createDeployStatus(…) 方法传递以下的参数:

  1. int severity 程度代码会封装到 IStatus 界面之中,并拥有值 IStatus.INFO(对于有内容的信息),IStatus.WARNING(对于警告性的信息)以及 IStatus.ERROR(对于错误信息)。根据程度不同,信息所显示的符号也不同(一个蓝色圆圈,一个黄色三角形,或者中间带一横杠的红色圆圈)。
  2. String validatorId 每一个确认器都有字符串代表的系统范围独特标识符。在我们的范例之中,标识符存储在静态的类变量之中,这样如有需要就可以从外边访问它了。
  3. String problemType 识别问题的标识符,解决机制从内部会访问该标识符。
  4. String unboundMessage 信息显示在图表之中。
  5. Object[] bindings 用于 Native Language Support(NLS)的数组与出错信息相绑定。在这里的范例之中,版本字符串的当前值会传递给 unboundMessage 字符串。值会在 unboundMessage 的占位符 {0} 上显示。
  6. DeployModelObject object 受到影响的模型对象。在这里的范例之中,我们直接向单元添加了状态信息。

测试确认器

现在您就可以测试确认器了:

  1. 当您在更新确认器方法时,您可以保存文件(Ctrl+s)并启动一个运行时环境。
  2. 从 Middleware 配置板折叠项中创建一个新的 MySQLDatabaseSystemUnit,并打开 Properties 视图Capabilities 项。
  3. 为 <no productName> capability(对于这里的锻炼,您可以使用 MySQL Database System),输入一个标题,并切换至 My SQL Version 属性。
  4. 输入一个无效的词,例如 test,并将鼠标直接放在单元的状态信息上(MySQLDatabaseSystemUnit 中带有大写字母 I 的蓝色圆圈),如图 7 所示。有两条信息被显示了出来:
    • 第一个是指示版本号无效的信息
    • 第二个是新单元的默认可选安装信息
图 7. MySQLDatabaseSystemUnit 失败的版本检查
版本检查失败的拓扑编辑器
版本检查失败的拓扑编辑器

图 7 的大图

注意:
在图 7 之中,注意单元右上角和左上角处的两个数字。这些数字指示了功能的数量以及单元所拥有的需求。您可以双击这些数字,以快速访问单元的功能与需求。您可以在拓扑编辑器的 Preferences 窗口中激活该可选特性:选择 Window > Preferences | Topology Editor > Unit Details 然后选择 Capabilities and requirements 选项。

  1. 现在,您可以将 My SQL Version 属性设置为一个典型的版本号,例如 5.1,并再次检查状态信息。只有可选的安装信息会显示出来。
  2. 保存图表,并关闭运行时环境。

该范例显示了确认单元的简单方式。您可以对 validateUnit(...) 方法添加更多的代码,以确认单元上的其他属性。您还可以执行更复杂的确认操作,例如确认该版本号与不同单元的版本号相协调。本文的其余部分会讨论确认单元的其他技术。

再使用已存在的属性确认器

除了编写所有的确认器,您可以使用核心确认框架所提供的不同已存在确认器。使用已存在的确认器支持再使用,并使得向定制域添加简单的确认器变得更加容易。举一个简单的范例,就是确认器,由它来决定是否设置一个属性值,以及一个属性是否拥有特定的值。

在这一部分中,您要向 MySQLDatabaseSystemUnitValidator 类添加两个已存在的 AttributeValidatorsclass,(a)如果 MySQLVersion 字符串是空的,(b)如果端口属性拥有 8080 的值,那么该类会报告警告信息,Apache Tomcat 之类的程序服务器将会使用 8080 这个值作为默认值,所以对于 MySQL 端口来说使用它并不是一个明智的选择。

  1. 在 MySQLDatabaseSystemUnitValidator 类中创建一个新的名为 addMyAttributeValidators() 的方法,并从如代码清单 4 所示的构造器方法中调用该方法。
清单 4. 其他 DeployAttributeValidators 的方法框架
..
protected MySQLDatabaseSystemUnitValidator(EClass unitType) {
...
   // call the new method
   addMyAttributeValidators();
}

protectedvoid addMyAttributeValidators() {
 // register your AttributeValidators here
...
}

您需要向您所使用的每一个预定义确认器分配一个独一无二的字符串标识符,如下一步所示:

  1. 添加来自代码清单 5 的两个类变量与源代码。您可以再次复制并粘贴 addMyAttributeValidators() 方法的内容,并点击 Ctrl+Shift+o 来再次修复导入。
  2. 保存对类所作的更改。
清单 5. 初始化已存在DeployAttributeValidators 的代码片段
...

publicfinalstatic String VERSION_NOT_EMPTY_ID = 
    "VERSION_NOT_EMPTY_ID";
publicfinalstatic String PORT_NOT_8080_ID = 
    "PORT_NOT_8080_ID";

...

protectedvoid addMyAttributeValidators() {
   // a. Warning if the version string is empty
   addAttributeValidator(new DeployAttributeStringNotEmptyValidator(
      MySQLDatabaseSystemUnitValidator.VERSION_NOT_EMPTY_ID,
      MysqlPackage.Literals.MY_SQL_DATABASE_SYSTEM__MY_SQL_VERSION,
      IStatus.WARNING));
   // b. Check that the port is not 8080
   addAttributeValidator(new DeployAttributeNotEqualsValidator(
      MySQLDatabaseSystemUnitValidator.PORT_NOT_8080_ID,
      MysqlPackage.Literals.MY_SQL_DATABASE_SYSTEM__PORT,
      new BigInteger("8080"),
      IStatus.WARNING));
}

该代码实现了单元确认器中的两个属性确认器,并使用 addAttributeValidator(…) 方法来注册它们。因此,每次在确认单元时都会调用属性确认器。

DeployAttributeStringNotEmptyValidator 会使用到三个输入参数:

  1. String validatorID 确认器的独特标识符。在我们的范例之中,我们会参考 VERSION_NOT_EMPTY_ID 所声明的类属性。
  2. EAttribute attribute 该确认器应该操作的属性。该参数会参考可以从 EMF 域包访问的 EMF 结构性特性(EAttribute)。
  3. int severity 该属性是信息的重要程度,IStatus 界面会再次使用到它。

DeployAttributeNotEqualsValidator 会接受相同的参数,要么是一个无效的值(如代码清单 5 所示)或者一个无效值的数组。如果属性的值与一个无效值相符合,那么就会出现警告信息了。

注意:
您必须为属性类型使用一个适当的确认器。DeployAttributeStringNotEmpty 确认器只适用于字符串属性,以及类型为扩展原始类型 xsd:string 的属性。DeployAttributeNotNull 确认器只适用于复杂的数据类型,例如端口(os:port)并检查它们拥有一个值。

在您编辑 MySQLDatabaseSystemUnitValidator 类之后,您可以测试运行时环境之中的更改。如果 MySQLVersion 属性拥有一个值,如图 8 所示的单元上会出现一个出错警告信息。如果您将端口属性的值设置为 8080,那么图中就会出现“端口值 8080 无效”的警告信息。在您完成测试之后您可以关闭运行时环境。

图 8. 来自已存在属性确认器的警告信息
警告信息的屏幕截图
警告信息的屏幕截图

使用其他预定义的确认器

有一些按照简单方式运行的其他预定义确认器。例如:

  • DeployAttributeInvalidPathnameValidator 会确保该文件和目录路径对于操作系统是适合的。
  • DeployAttributeRestrictedValueValidator 会限制预定义值的输入区域。

您可以点击源代码中的属性确认器,来得到所有属性确认器的列表,然后打开类型层级结构浏览器(F4)并选择 DeployAttributeValidator 类。打开内容菜单并选择 Focus On 'DeployAttributeValidator',然后查看一下显示的亚类。

创建您自己的 DeployAttributeValidator

如果您拥有复杂的确认器,或者如果您想要再使用确认源代码,那么您可以将 DeployAttributeValidator 类作为亚类,并实施 validate(…) 方法来创建您自己的属性确认器,它证实了属性值是由多个 1024 组成的。然后您可以根据属性值的 MySQL 推荐来使用确认器来选择 MAX_ALLOWED_PACKET 属性。

  1. 在 Project Explorer 中点击 org.example.mysql.internal.validator 包,打开下拉菜单,并选择 New > Class
  2. 输入类名作为 MyAttributeValidator
  3. 在 Superclass 区域附近,点击 Browse 以指定新确认器的超类。
  4. 在接下来的对话框窗口之中,输入 DeployAttributeValidator,选择匹配的类,并点击 OK
  5. 从超类复选框中选择 Constructors 并点击 Finish

类的框架会生成,现在您就可以编辑确认方法:

  1. 在 MyAttributeValidator 类中,使用来自代码清单 6 的确认方法来替换 validate(…) 方法,并添加 createNotNullOrZeroStatus(…) 帮助类方法,它包含在代码清单 6 之中。
  2. 修复所有的导入(Ctrl+Shift+o)并保存更改。
清单 6. DeployAttributeValidator 的 validate(…) 方法
...
@Override
publicvoid validate(DeployModelObject object,
 IDeployValidationContext context, IDeployReporter reporter) {
   // get the value of the attribute from the super class
   Object value = super.getAttributeValue(object);
   // check that the object is neither null nor zero
   if (value != null) {
      // convert the value into int
      int val = ((Integer) value).intValue();
      if (val != 0) {
         // test if multiple of 1024
         if (val % 1024 != 0) {
             // if not, create a status and add it to the reporter
             reporter.addStatus(DeployCoreStatusFactory.INSTANCE
                .createDeployStatus(
                    IStatus.ERROR,
                    super.getValidatorID(),
                    "MaxAllowedPackageMustBeAMultipleOf1024",
                    "Value of attribute MaxAllowedPackage, \"{0}\" should be a " + 
                    "multiple of 1024",
                    new Object[] {value},
                    object));
         }
      } else {
        this.createNotNullOrZeroStatus(object, context, reporter);
      }
   } else {
     this.createNotNullOrZeroStatus(object, context, reporter);
   }
}

privatevoid createNotNullOrZeroStatus(DeployModelObject object, 
      IDeployValidationContext context, IDeployReporter reporter) {
   reporter.addStatus(
      DeployCoreStatusFactory.INSTANCE.createDeployStatus(
          IStatus.ERROR,
          super.getValidatorID(),
          "AttributeNullOrZero",
          "Max Allowed Package should not be null or zero",
          new Object[] {},
          object));
}
  1. 最后,您可以实现 MySQLDatabaseSystemUnitValidator 类中的新确认器,如代码清单 7 所示,并保存更改。
清单 7. 向 Unit Validator 类添加新确认器
...
publicfinalstatic String MAX_ALLOW_PACKAGE_VALIDATOR_ID = 
       "MAX_ALLOW_PACKAGE_VALIDATOR_ID";
...
protectedvoid addMyAttributeValidators() {
...
   // c. Check that max_allowed_packet is multiple of 1024 
   addAttributeValidator(
      new MyAttributeValidator(
        MySQLDatabaseSystemUnitValidator.MAX_ALLOW_PACKAGE_VALIDATOR_ID,
        MysqlPackage.Literals.MY_SQL_DATABASE_SYSTEM__MAX_ALLOWED_PACKET));
...
}
...

新的 MyAttributeValidator 类由一个构造器方法,一个继承 validate(…) 方法,以及一个 createNotNullOrZeroStatus(…) 帮助方法组成。构造器拥有两个输入参数,它们会传递给超类(super(validatorID, attribute);)的构造器方法:

  1. 字符串 validatorID 单独的标识符
  2. EAttribute attribute 确认器操作的属性

validate(…) 方法的输入参数与 添加一个简单的单元确认器方法 部分中 validateUnit(…) 方法的输入参数相同。validate(…) 方法包含了以下的操作:

  1. 获得了属性的值::
    Object value = super.getAttributeValue(object);
  2. 值被设置成 null。
  3. 如果值尚未为 null,那么它会被转化为一个 int 值:
    ( intval = ((Integer) value).intValue();)
  4. 然后值被设置为 zero。
  5. 如果值尚未为 zero,那么值为多个 1024 时就会得到检查。如果不是,那么就会创建一个出错信息。

如果属性的值是 null 或者 0,那么就会调用 createNotNullOrZeroStatus(…) helper 方法。该方法会分割到不同的方法以避免复制代码。

您可以在运行时环境之中再次测试更改。如果您输入了有多个 1024 的值,那么出错信息就不会再出现了。

该属性确认器包含了一个非常简单的规则;确认器可以尽可能的简单。这部分的目标在于,向您展示怎样从已存在的 API 中获益,以及怎样创建您自己的确认器库。在属性确认器周围有一些用例。有了您自己的确认器类,您就可以在不同的项目和技术扩展之中重复使用规则。

在接下来的部分之中,我们将会保留属性确认器不变,并演示怎样确认单元之间的链接。

检查带有域确认器的链接及类型

每一个单元都有与其他单元的不同关系及附属。有时,您可能想要确认这些关系,并报告关于它们的状态信息。在我们的 MySQL 范例之中,每一个 MySQLDabaseSystemUnit 都安装有至少一个 DatabaseInstanceUnit,它是在存储程序数据的数据库域中的相应单元。在这一部分之中,您可以将这些确认规则添加至 MySQLDatabaseSystemUnitValidator 的 validateUnit(…) 方法。

  1. 打开 MySQLDatabaseSystemUnitValidator 类,并为确认器标识符向源代码添加一个新的类属性(见于代码清单 8)。
  2. 切换至 validateUnit(…) 方法,并在检查版本号码的代码之后,添加来自代码清单 8 的源代码。
  3. 点击 Ctrl+Shift+o 来修复导入问题。当您要选择一个类以代表 List 对象时,您可以选择 java.util.List 界面。
清单 8. 检查在 MySQLDatabaseSystem 中至少有一个 DatabaseInstanceUnit 的代码片段
...
publicfinalstatic String MY_SQL_DATABASE_SYSTEM_HOSTING_WARNING_ID = 
       "MY_SQL_DATABASE_SYSTEM_HOSTING_WARNING_ID";
...
publicvoid validateUnit(Unit unit, 
       IDeployValidationContext context, IDeployReporter reporter) {
   super.validateUnit(unit, context, reporter);
   // version check
...
   // hosting check
   // get all hosted units inside the MySQLDBUnit
   // that are the type of DATABASE_INSTANCE_UNIT
   List<Unit> hostedInstances = 
      ValidatorUtils.getHosted(unit,
         DatabasePackage.Literals.DATABASE_INSTANCE_UNIT);
   if (hostedInstances.size() < 1) {
      IDeployStatus stat = 
          DeployCoreStatusFactory.INSTANCE.createDeployStatus(
             IStatus.WARNING,
             MySQLDatabaseSystemUnitValidator.MY_SQL_DATABASE_SYSTEM_HOSTING_WARNING_ID,
             "MissingDatabaseInstanceUnitOnMySQLDatabaseSystem",
             "At least one DatabaseInstanceUnit should be hosted on MySQLDatabaseSystem.",
             new Object[] {},
             unit);
      reporter.addStatus(stat);
   }
}

该确认器会使用来自 ValidatorUtils 的 getHosted(…) 方法,来获得一系列的单元,该单元可以指定单元安装。这里的范例会使用到以下的输入参数:

  1. 单元 unit 当前的单元,在这里的范例之中,就是确认的 MySQLDatabaseSystem 单元。
  2. EClass hostedUnitType 您还可以选择限制安装元素的列表,以指定单元的类型。在这种情况下,返回的列表应该只包含 DatabaseInstanceUnits。因此,我们会使用来自数据库技术扩展 DatabasePackage 界面的 DatabasePackage 界面的 DatabaseInstanceUnit 类型。

如果 DatabaseInstanceUnits 所返回的列表是空的,它表示了 MySQLDatabaseSystem 单元并没有安装 DatabaseInstanceUnits,接着就会出现出错信息。

  1. 检查运行时环境之中的结果。

注意:
您可以在图表中点击 Ctrl+t 并输入 Database Instance 来添加一个新的 DatabaseInstanceUnit。如果您尚未向 MySQL 单元添加 DatabaseInstanceUnit,那么您将会在图表中看到出错信息。图 9 是两个 MySQLDatabaseSystemUnits 及其相关状态信息的集合,一个有,另一个没有 DatabaseInstanceUnit。

ValidatorUtils 类包含了许多有用的方法,以访问单元(包含功能,需求,限制性因素)的结构性元素,并获取关于单元关系的信息。在大多数情况下,您可以应用 ValidatorUtils 类的一个静态方法,并不需要混合单元所生成的 EMF API。

图 9. 两个 MySQLDatabaseSystemUnits 所演示的安装确认
两个 MySQLDatabaseSystemUnits 之上的状态信息
两个 MySQLDatabaseSystemUnits 之上的状态信息

使用 Domain Validator 类来确认拓扑

到目前为止,我们已经演示了不同种类的单元和属性确认器。在这一部分之中,我们向您展示了怎样更新域确认器类,以确认图表之中的一系列单元。为了继续学习我们的范例,您可以考虑这样一种情况,您应该在操作系统之上安装两个 MySQL 数据库系统(例如,在测试环境之中)。每一个 MySQL 数据库系统都会通过一个端口与其他的程序相交流。在我们的范例之中,我们必须确保每一个数据库系统都使用它自己的端口。

作为第一步,您要为运行时环境中的该范例创建测试环境。您还可以选择从 下载 部分下载 DomainValidatorRuntimeExample 范例,并将其导入到运行时环境之中。

  1. 打开运行时环境,并创建一个新的拓扑。
  2. 向图表添加两个 MySQLDatabaseSystem 单元,并解决来自上一个范例的警告信息。
  3. 向图表添加一个操作系统(例如,一个 SUSE Linux Server 9)以及一个 x86 服务器(来自硬件折叠项)。
  4. 为操作系统设置根密码,并在硬件之上安装操作系统。
  5. 在操作系统上安装 MySQLDatabaseSystemUnits。
  6. 向操作系统添加 Port Consumer 功能。如果您向 Add Capability 对话框窗口的文本框输入 os.Port,就可以找到功能了。
  7. 从配置项向图表添加一个 Port Configuration 单元,并给端口起一个名字。
  8. 在操作系统上安装端口配置。
  9. 向 MySQLDatabaseSystemUnits 添加一个新的需求,将 Caption 设置为 port configuration,并将 Type 设置为 os.Port

其他所有的参数可以放到默认的配置之中。如果您完成了配置操作,那么每一个 MySQLDatabaseSystemUnit 都显示了警告信息“未完成端口配置需求”。

  1. 创建从每一个 MySQLDatabaseSystemUnit 到操作系统上端口配置单元附属链接,来解决这些出现的警告信息。这些链接会解决图表上的错误,但是该安排因为多个端口使用问题的存在于实际的系统中不会发挥作用。因此,一个确认器必须指出这些问题。

图 10 显示了 DatabaseB 单元中端口需求的完整范例。

图 10. 域确认器范例的初始拓扑
2 MySQLDatabaseSystemUnits 取决于端口 1
2 MySQLDatabaseSystemUnits 取决于端口 1

图 10 的大图

为了在图 10 中所示的配置上显示出错信息,您可以向 PortConfiguration 单元添加一个确认器,该单元报告了来自 MySQLDatabaseSystemUnits 的附属链接。更好的方法是将确认逻辑置于 MySQL 域(MysqlDomainValidator 的域确认器类。

该范例的确认器显示在代码清单 9 之中。您可以将方法复制并粘贴到 MysqlDomainValidator 类,修复导入(Ctrl+Shift+o),并选择 java.util.Iteratorjava.util.List 作为导入的类。

清单 9. 检查 MysqlDomainValidator 类中端口用例的代码片段
... 
@Override
publicvoid validate(IDeployValidationContext context, 
    IDeployReporter reporter) {
   // call validator method of super class
   super.validate(context, reporter);
   // get all MySQLDatabaseSystemUnits
   Iterator<MySQLDatabaseSystemUnit> it = 
	context.findAllUnits(MysqlPackage.Literals.MY_SQL_DATABASE_SYSTEM_UNIT);
   String message = "Multiple Port Usage: \"{0}\"";
   Set<PortConfigUnit> portConfigs = new HashSet<PortConfigUnit>();
   // iterate over the the units
   while (it.hasNext()) {
      MySQLDatabaseSystemUnit mysqlDBSystem = it.next();
      // get all requirements of the mysql unit
      List<Requirement> reqs = mysqlDBSystem.getRequirements();
      for (Requirement req : reqs) {
         // get the link target of each requirement
         Capability cap = ValidatorUtils.getDependencyLinkTarget(req);
         // check if link target is PortConfigUnit type
         if (cap != null && ValidatorUtils.getUnit(cap) instanceof PortConfigUnit) {
            PortConfigUnit portConfigUnit = (PortConfigUnit) cap.getParent();
            // check if PortConfiguration is in use by other Mysql DB Systems
            if (portConfigs.contains(portConfigUnit)) {
               // if yes: create an Error message
               IDeployStatus status = 
                  DeployCoreStatusFactory.INSTANCE.createDeployStatus(IStatus.ERROR,
                     "DomainValidID",
                     "MultiplePortUsage",
                     message,
                     new Object[] { portConfigUnit.getDisplayName()},
                     portConfigUnit);
               reporter.addStatus(status);
            } else {
              // if not: add portConfigUnit to used PortConfigurations
              portConfigs.add(portConfigUnit);
            }
         }
      }
   }
}
...

您可以按照以下的步骤来为该范例实施确认器检查操作:

  1. 超类的 validate(…) 方法得到调用,以确保执行了所有获得的确认器。
  2. 从传递给 validate(…) 方法的内容对象之中,会获得所有的 MySQLDatabaseSystemUnits 以及以下的代码:
    context.findAllUnits(…)。方法会随着一个指定想要获得元素类型的输入参数一起获得。在本文的其他确认器中,可以从 LITERALS 界面中得到类型:
  3. 对于列表之中的每一个 MySQLDatabaseUnit,可以得到需求并存储在一个列表之中:
    List<Requirement> reqs = mysqlDBSystem.getRequirements();
  4. 在接下来的一步中,得到了每一个链接的目标:
    Capability cap = ValidatorUtils.getDependencyLinkTarget(req);
  5. 功能是根据 if 语句的第一部分获得的。
  6. 包含功能的单元获得了(cap.getParent()),并检查它是否是一个 PortConfigUnit。(记住 附属需求 总会连接至单元的 功能。因此,您需要获得功能的父类以检查单元)。
  7. 如果单元是 PortConfigUnit。那么您可以检查单元尚未列于一个系统(单独元素的列表)。如果单元尚未存在的话,那么您可以将其置于系列之中。如果它已经存在于系列了,那么 PortConfigUnit 仍然在使用当中,然后就会创建一个出错信息。

图 11 显示了结果得到的出错信息。.

图 11. 来自 DomainValidator 的出错信息
One IP_Interface 需求必须得到声明
One IP_Interface 需求必须得到声明

正如您所看到的那样,您可以添加复杂的确认器,它会影响到带有所有单元的整个拓扑。您可以尽情地添加代码以确认域,但是您要记住调用超类的确认器方法,以确保拓扑编辑器能够完成所有需要的确认器。

创建一个确认器项目

本文中的上一个范例向您展示了怎样直接向定制技术域和生成的源代码添加确认器。在这一部分中,我们将会向您展示怎样在单独的项目之中创建确认器,在以下的案例中这点将会很有用:

  • 您想要 向已存在的模型元素添加一个确认器 (核心单元类型),但是不能访问源代码。
  • 为了 改进源代码维护 ,您应该从技术域中分割确认器源代码。
  • 在不同的定制技术域中再次使用新 确认器 (例如,如果您编写了定制的 AttributeValidator 的话)。

我们在接着学习例子时,我们想要确保每一个 PortConfigUnit 都访问了 IPInterfaceUnit,它处理了网络连接问题。默认条件下,只有 PortConfigUnit 的需求拥有 PortConsumer 的需求。在本范例中,如果 PortConfigUnit 尚未与 IPInterface 的附属连接相联系,那么我们就要创建一个出错信息了(见于图 12)。

图 12.带有出错信息(上层单元)以及需求(下层单元)的 PortConfigUnits
带有不同配置的 2 PortConfigUnits
带有不同配置的 2 PortConfigUnits
  1. 创建一个新的插件项目:
    1. 选择 File > New > Project > Plug-in Development > Plug-in Project 然后点击 Next
    2. 将新项目命名为 org.example.mysql.validation,并点击 Next 继续操作。
    3. 保持其他默认参数的设置不变,并点击 Finish

向导会自动创建插件框架,并在工作区域之中打开插件编辑器。

  1. 打开插件编辑器的 Dependencies 项,并向 Required Plug-ins 部分添加以下的插件:
    1. 资源插件,org.eclipse.core.resources,以访问 Eclipse API。
    2. 拓扑编辑器所使用的插件:
      • 核心 API:com.ibm.ccl.soa.deploy.core
      • 访问 IPInterface 声明的 Network API 的插件:
        com.ibm.ccl.soa.deploy.net
      • 访问 PortConfigUnit 的操作系统 API 插件:
        com.ibm.ccl.soa.deploy.os

注意:
为了改进 Add 选项的包选项,您可以在对话框窗口的文本区域之中输入插件名。然后选项会得到筛选,以匹配插件。在这里,您还可以使用占位符,例如星号,如果您选择 OS 包,那么您可以输入 *.deploy.os

  1. 使用 Ctrl+s 来保存编辑器中所做的更改。

接下来的一步是使用插件注册确认器。

  1. 打开插件编辑器的 Extensions 项。
  2. 点击 Add 并选择 com.ibm.ccl.soa.deploy.core.domains 扩展点,
  3. 点击 Finish
  4. 回到插件编辑器,编辑 Extension Element Details 表单,并设置以下的值:
    • 名字:MyDomain
    • Id:org.example.mysql.validation
    • targetNamespace:http://www.ibm.com/ccl/soa/deploy/os/1.0.0/
  5. 在 com.ibm.ccl.soa.deploy.core.domains 之下右击域条目,并选择 New > validator 来向扩展添加一个确认器,如图 13 所示。
图 13. 向域添加一个确认器
下拉菜单是 plugin.xml Extensions 项
下拉菜单是 plugin.xml Extensions 项
  1. 在插件编辑器右边的 Extension Element Details 之中,现在您可以选择一个已存在的确认器类,或者创建一个新的确认器类(如该案例所示)。
  2. 点击 class* 链接,它将会打开 New Java Class 对话框窗口。
  3. 输入 PortConfigDomainValidator 作为类名。
  4. Superclass 区域之中,指定:
    com.ibm.ccl.soa.deploy.core.validator.pattern.UnitDomainValidator
  5. Constructors from superclassInherited abstract methods 选择复选框,并点击 Finish

新确认器类现在得到了生成,并在工作区中打开。现在您可以使用源代码来编辑新确认器的内容。

  1. 从代码清单 10 向确认器类添加构造器方法以及 validate(…) 方法。
  2. 完成导入(Ctrl+Shift+o)并保存更改(Ctrl+s)。
清单 10. 完成 PortConfigDomainValidator 的代码片段
... 

public PortConfigDomainValidator() {
   this(OsPackage.eINSTANCE);
}

@Override
publicvoid validate(IDeployValidationContext context, 
    IDeployReporter reporter) {
   // call validator method of super class
   super.validate(context, reporter);
   // get all PortConfigUnits of the topology
   Iterator<PortConfigUnit> it = 
	context.findAllUnits(OsPackage.Literals.PORT_CONFIG_UNIT);
   // iterate through all PortConfigUnits
   while (it.hasNext()) {
      PortConfigUnit portConfigUnit = it.next();
      // from each PortConfigUnit get all requirements of type IP_Interface
      List<Requirement> requirements = 
         ValidatorUtils.getRequirements(
         portConfigUnit, 
         NetPackage.Literals.IP_INTERFACE);
      if (requirements != null && requirements.size() != 1) {
         // if there is no or there are too many IP_Interfaces, report an error
         reporter.addStatus(
            DeployCoreStatusFactory.INSTANCE.createDeployStatus(
              IStatus.ERROR,
              "PORT_CONFIG_DOMAIN_VALIDATOR_ID",
              "MissingIPInterfaceRequirement",
              "Exactly one IP_Interface requirement has to be declared.",
              new Object[] {}, portConfigUnit));
      }
   }
}

确认器插件会使用 Eclipse 的扩展点,以注册新功能。

在步骤 5 之中,选择 com.ibm.ccl.soa.deploy.core.domains 扩展点,它赋予了您添加新 domain validator 功能的能力。该域确认器与特定的域相关,它随着目标名字区一起配置。因为 PortConfiguration 单元位于操作系统域之中,我们会为该域设置相应的 targetNamespace 属性(http://www.ibm.com/ccl/soa/deploy/os/1.0.0/)。

然后您可以创建一个来自 UnitDomainValidator 的新类,您可以从中添加一个新构造器方法以及 validate(…) 方法。在构造器方法中,您可以将操作系统域注册为目标域(OsPackage.eINSTANCE)。validate(…) 方法包含了以下的指南:

  1. 超类的确认方法叫做:super.validate(...)
  2. 当前拓扑的所有l PortConfigUnits 会随着内容对象的 findAllUnits(…) 方法获得。获得的类型会再次从 LITERALS 界面作为输入参数传递给方法。
  3. findAllInstances(…) 方法的返回类型是 java.util.Iterator,它指向了 PortConfigUnits 集合。
  4. 对于收集之中的每一个 PortConfigUnit,需求会得到决定。ValidatorUtils 类与方法 getRequirements(…) 会再次随着以下的属性得到调用:
    1. Unit 单元 确认当前的单元。在这种情况之下,当前的 PortConfigUnit 会传递给方法。
    2. EClass 类型 应该获得需求的类型。因为我们想要检查确实只有一个 net.IpInterface 需求得到了配置,会从 NetPackage's Literals 界面获得相应的 EMF 类:
      NetPackage.Literals.IP_INTERFACE
  5. getRequirements(…) 方法的返回类型是一个 java.util.List,您可以将其选中以查看它是否是只包含一个元素。如果不是,那么就会出现一个出错信息,并添加至报告器。

您可以在运行时环境之中测试新确认器。如果您向一个图表添加新 PortConfigUnit,现在您可以看到如图 12 所示相似的出错信息。如果您创建了一个新的需求,并将类型设置为 net.IpInterface,那么出错信息机会消失了。

有了单独的确认器项目,您就可以添加尽可能多的确认器,或者向拓扑编辑器的已存在技术域添加。进入点是 com.ibm.ccl.soa.deploy.core.domains 扩展点,您可以将其注册为一个新的域确认类。从该域确认器类中,您可以实现并注册您自己的单元和属性确认器。

总结

在本文之中,我们将会向您展示确认机制是如何极大地改进不同抽象层次之上的技术域扩展的。您可以在属性,单元,功能与域上添加确认器,您可以向用户将状态报告为信息,警告或者错误信息。定制确认器可以包含具体的逻辑,以通过 API 检查拓扑的元素,例如 ValidatorUtils 类的静态方法。在大多数情况下,对于编辑和超越已存在的 validate(…) 方法来说已经足够了。对于更复杂的确认来说,您还可以使用 Rational Software Architect 部署规划工具所提供的 API,以添加拥有自己规则的确认器项目。

在技术域扩展中拥有确认器,对建模者增加了该域的价值。改进定制域的下一步是添加解决机制,以解决定制域中由确认器所发现的问题。


下载资源


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Rational
ArticleID=757326
ArticleTitle=使用 Rational Software Architect 中的拓扑编辑器来添加一个定制确认器
publish-date=09132011