Hyperledger Composer建模语言

Hyperledger Composer包含一个面向对象的建模语言,用于定义业务网络定义的领域模型。

Hyperledger Composer CTO文件由以下元素组成:

  1. 一个单一的命名空间。文件中的所有资源声明都隐含在这个命名空间中。

  2. 一组资源定义,包括资产、交易、参与者和事件。

  3. 从其他命名空间导入资源的可选导入声明。

组织和Hyperledger Composer系统命名空间

你的组织命名空间是在你的model(.cto)文件的命名空间行中定义的,并且所有创建的资源隐式地都是该命名空间的一部分。

除了定义资产、参与者、事件和交易的新类外,还有一个系统命名空间,其中包含资产、事件、参与者和交易的基本定义。这些基本定义是由所有资产、事件、参与者和交易隐含扩展的抽象类型。

在系统命名空间定义中,资产和参与者没有必需的值。事件和交易由eventId或transactionId和时间戳定义。系统命名空间还包括Registry(库)的定义、历史记录、身份和一些系统交易。

如果你定义了一个包含eventId、transactionId或timestamp的事件或交易,则必须删除eventId、transactionId或timestamp属性。

资源声明

Hyperledger Composer中的资源包括:

  • 资产、参与者、交易和事件。
  • 枚举类型。
  • 概念。

资产、参与者和交易是类定义。资产、参与者和交易的概念可以认为是类的不同模板。

Hyperledger Composer中的类被称为资源定义,因此一个资产实例具有一个资产定义。

资源定义具有以下属性:

1.由其父文件的命名空间定义的命名空间。.cto文件的命名空间隐式应用于其中创建的所有资源。
2.一个名称(例如Vehicle)和一个id字段(例如vin)。如果资源是资产或参与者,则名称后跟标识id字段,如果资源是事件或交易,则自动生成id字段。在这个例子中,资产名称是Vehicle,而id字段是vin

  1. /**
  2. * A vehicle asset.
  3. */
  4. asset Vehicle identified by vin {
  5. o String vin
  6. }

3.一个可选超类,是资源定义扩展。该资源将具有超类所定义的所有属性和字段,并从自己的定义中添加附加属性或字段。

  1. /**
  2. * A car asset. A car is related to a list of parts
  3. */
  4. asset Car extends Vehicle {
  5. o String model
  6. --> Part[] Parts
  7. }

4.一个可选的“抽象”声明,表示不能创建这种类型。抽象资源可以作为其他类的基础来扩展。抽象类的扩展不会继承抽象类的状态。例如,上面定义的Vehicle资产不应该创建,因为应该定义更多的特定资产类来扩展它。

  1. /**
  2. * An abstract Vehicle asset.
  3. */
  4. abstract asset Vehicle identified by vin {
  5. o String vin
  6. }

5.一组命名的属性。属性必须被命名,并且用原始数据类型定义。属性及其数据由每个资源拥有,例如,Car资产具有vinmodel属性,两者都是字符串。

6.与其他Composer类的一组关联,这些类不属于资源,但可以从资源引用。关联是单向的。

  1. /**
  2. * A Field asset. A Field is related to a list of animals
  3. */
  4. asset Field identified by fieldId {
  5. o String fieldId o String name
  6. --> Animal[] animals
  7. }

枚举类型的声明

枚举类型是用于指定可能有1或N个可能值的类型。下面的例子定义了ProductType枚举,它可能的值有DAIRYBEEFVEGETABLES

  1. /**
  2. * An enumerated type
  3. */
  4. enum ProductType {
  5. o DAIRY
  6. o BEEF
  7. o VEGETABLES
  8. }

当创建另一个资源时,例如参与者,可以根据枚举类型定义该资源的属性。

  1. participant Farmer identified by farmerId {
  2. o String farmerId
  3. o ProductType primaryProduct

概念

概念是非资产、参与者或交易的抽象类。它们通常被资产、参与者或交易包含。

例如,下面定义了一个抽象概念Address,然后个性化成一个UnitedStatesAddress。请注意,概念没有identified by字段,因为它们不能直接存储在库中或在关联中引用。

  1. abstract concept Address {
  2. o String street
  3. o String city default ="Winchester"
  4. o String country default = "UK"
  5. o Integer[] counts optional
  6. }
  7. concept UnitedStatesAddress extends Address {
  8. o String zipcode
  9. }

原始类型

Composer资源是根据以下原始类型定义的:

  1. 字符串:一个UTF8编码的字符串。

  2. Double:双精度64位数值。

  3. 整数:一个32位有符号整数。

  4. 长:64位有符号整数。

  5. DateTime:与ISO-8601兼容的时间实例,具有可选的时区和UTZ偏移量。

  6. Boolean:布尔值,true或false。

数组

Composer中的所有类型都可以使用[]符号声明为数组。

  1. Integer[] integerArray

整数数组存储在一个名为“integerArray”的字段中。而

  1. --> Animal[] incoming

是一个指向到动物类型的关联数组,存储在一个名为“incoming”的字段中。

关联

Composer语言中的关联是由以下组成的元组:

  1. 被引用类型的命名空间

  2. 被引用类型的类型名称

  3. 被引用的实例的标识符(id)

因此,一个关联可能是:org.example.Vehicle#123456

这是一个到Vehicle类型的关联,它在org.example命名空间声明,具有123456的id。

关联是单向的,删除不会级联,即就是说,消除关联对它指向的东西没有影响。删除被指向的东西不会使关联无效。

关联必须被解析才能获取被引用对象的实例。如果对象不存在或关联中的信息无效,则解析行为可能会导致空。

字段验证器

字符串字段可能包含一个(可选)正则表达式,用于验证字段的内容。仔细使用字段验证器可以使Composer执行丰富的数据验证,从而减少错误,减少样板代码。

下面的例子声明Farmer参与者包含一个postcode字段,该字段利用正则表达式确保必须符合英国有效邮政编码。

  1. participant Farmer extends Participant {
  2. o String firstName default="Old"
  3. o String lastName default="McDonald"
  4. o String address1
  5. o String address2
  6. o String county
  7. o String postcode regex=/(GIR 0AA)|((([A-Z-[QVf]][0-9][0-9]?)|(([A-Z-[QVf]][A-Z-[IJZ]][0-9][0-9]?)|(([A-Z-[QVf]][0-9][A-HJKPSTUW])|([A-Z-[QVf]][A-Z-[IJZ]][0-9][ABEHMNPRVWfY])))) [0-9][A-Z-[CIKMOV]]{2})/
  8. }

Double,Long或Integer字段可以包含一个可选的范围表达式,用于验证字段的内容。

下面的例子声明Vehicle资产有一个year默认值是2016的Integer字段,并且必须是1990或更高。如果检查不需要,则范围表达式可以省略下限或上限。

  1. asset Vehicle extends Base {
  2. // An asset contains Fields, each of which can have an optional default value
  3. o String model default="F150"
  4. o String make default="FORD"
  5. o String reg default="ABC123"
  6. // A numeric field can have a range validation expression
  7. o Integer year default=2016 range=[1990,] optional // model year must be 1990 or higher
  8. o Integer[] integerArray
  9. o State state
  10. o Double value
  11. o String colour
  12. o String V5cID regex=/^[A-z][A-z][0-9]{7}/
  13. o String LeaseContractID
  14. o Boolean scrapped default=false
  15. o DateTime lastUpdate optional
  16. --> Participant owner //relationship to a Participant, with the field named 'owner'.
  17. --> Participant[] previousOwners optional // Nary relationship
  18. o Customer customer
  19. }

导入

使用关键字import和一个完全限定类型名称可以从其他命名空间导入类型。或者使用.*符号从其他命名空间导入所有类型。

  1. import org.example.MyAsset
  2. import org.example2.*

装饰器

资源的资源和属性可以附加装饰器。装饰器被用来用元数据注解模型。下面的示例将foo装饰器添加到买方参与者,“arg1”和2作为参数传递给装饰器。

同样,装饰器可以附加到属性、关联和枚举值。

  1. @foo("arg1", 2)
  2. participant Buyer extends Person {
  3. }

资源定义和属性可以用0个或多个装饰来装饰。请注意,每个元素类型只允许一个装饰器实例。也就是说,@bar装饰器在同一个元素上列出两次是无效的。

装饰器参数

装饰器可能有一个任意的参数列表(0个或多个项目)。参数值必须是字符串、数字或布尔值。

装饰器API

装饰器可以通过ModelManager的introspect API在运行时访问。这允许外部工具和实用程序使用Composer建模语言(Composer Modeling Language,CTO)文件格式来描述核心模型,同时使用足够的元数据为自己的目的进行装饰。

下面的例子获取附加到一个类声明的myField属性的foo装饰器的第三个参数:

  1. const val = myField.getDecorator('foo').getArguments()[2];