软件体系结构描述语言(ADL)

软件体系结构描述语言(ADL)

要点浏览

本章将对学术界常见的体系结构描述语言进行介绍. 由于研究流派不同, 各种ADL 的设计和能力也不尽相同. 本章选取五种比较典型的ADL 作为代表, 希望能让读者了解主流ADL 的基本能力, 主要功能和应用范围. 为了让读者对各种ADL 有一个更为清晰的认识, 本章最后还对这五种典型的ADL 进行了比较全面的比较. 通过本章的学习, 您将能:

了解主流ADL 的语法和语义

掌握主流ADL 的特点

区分主流ADL 的不同

总体介绍

任何一个软件系统都有结构, 在系统开发过程中的分析设计阶段, 通过考察系统的结构, 可以对系统的开发和实现提供良好的基础. 系统的结构往往体现为系统的各个部分之间的配置. 对于描述软件系统配置的表示法的研究由来已久. 早在1975年,DeRemer 和Kron 就设计了模块互连语言(Module Interconnection

Language,MIL) 用于描述结构化的基于模块的程序. 在MIL 中, 模块可能需要导入/导出各种资源. 所谓的" 资源" 就是命名元素, 例如类型定义, 常量, 变量, 函数等.MIL 的编译器通过进行模块间的类型检查来保证系统的完整性, 常见的检查包括:某个模块要使用的资源是否已经被其它模块提供了, 资源的类型是否匹配, 一个模块的实现是否确实提供了其规约中声明的资源, 一个模块是否有权访问它要使用的资源等.

早期的MIL 要求不同模块的开发人员在开发前先达成很多一致. 例如:能够根据简单的名字匹配来发现模块之间的交互, 所有的模块都是用同一种语言开发的, 所有的模块在组装系统时都可用, 模块的接口描述了与之进行交互的其它模块……进一步的研究逐步弱化了这些限制. 例如Darwin 允许模块在运行时动态的实例化并进行绑定;Polygen 允许不同的模块用不同的编程语言进行开发. 各种软件配置的表示法逐渐成熟, 它们既能描述静态也能描述动态的结构化的分布式系统. MIL 的关注点是模块及其之间的互连. 随着系统复杂度的提高, 人们发现模块之间的交互逐步变得复杂. 研究人员对模块之间交互的重视导致了" 连接子

"(connector)这个概念的诞生, 它主要用于描述软件系统的各个组成部分

(component)即构件之间的交互关系. 从而软件系统的结构可以自然的用构件, 连接子及其之间的配置进行描述. 将连接子作为与构件同等重要的一阶实体进行处理, 是因为如果不将构件之间的交互显式的进行描述, 将会带来一些问题, 包括: 难以将构件之间的交互信息局部化, 从而导致难以识别系统中的连接, 并且难以复用连接机制

构件之间的关系难以进行抽象, 从而阻碍对整个系统结构的理解

由于构件的实现和交互信息绑定在一起, 对不同构件的使用往往会因为交互机制的不兼容而产生严重的集成问题.

支持构件, 连接子及其配置的描述语言就是如今所说的体系结构描述语言

(Architecture Description Language,ADL ).UniCon 就是最早出现的一种体系结构描述语言. 此外, 典型的ADL 还包括:

Rapide:一种事件驱动的ADL , 它以体系结构定义作为开发框架, 支持基于构件的开发. 该语言提供了建模, 分析, 仿真和代码生成的能力, 但是没有将连接子显式地表示为一阶实体.

Wright:其主要特点是将CSP 用于软件体系结构的描述, 从而完成对体系结构描述的某些形式化推理(包括相容性检查和死锁检查等). 但它仅仅是一个设计规约语言, 只能用于描述, 无法支持系统生成, 同时CSP 的使用也是比较困难的事情. Acme:支持ADL 之间的映射及工具集成的体系结构互交换语言. 其目标是作为体系结构设计的一个共同的互交换格式, 以便将现有的各种ADL 在这个框架下统一起来; 而它本身也可以看作是一种ADL .

xArch:一种基于XML 的ADL . 它使用XML 定义了描述体系结构的核心元素, 可

以用来简单的描述软件体系结构, 也可以作为设计其它ADL 的基础, 或者用作体系结构描述描述语言的互交换机制.

xADL2.0:以xArch 为基础的基于XML 的ADL . 除了xArch 的核心元

素,xADL2.0 还提供了对系统运行时刻和设计时刻的元素的建模支持, 类似版本, 选项和变量等更高级的配置管理观念, 以及对产品家族的体系结构的建模支持. 此外,xADL2.0还利用XML 的可扩展性简化了新的ADL 的设计及其相应工具的开发过程.

各种ADL 的出现为描述软件系统的结构提供了一种形式化的描述方法, 而不是容易引起歧异的线框图. 这种精确的描述也使得设计人员能够在系统开发的早期阶段对系统结构进行高层的分析和验证, 从而有助于提高软件开发质量, 降低开发成本.

以下我们将着重介绍五种ADL :UniCon,Darwin,C2 SADL,Acme和xADL. 常见的体系结构描述语言

UniCon (Universal Connector)

UniCon 简介

UniCon 是由CMU 和SEI 设计的一个体系结构描述语言. 该语言关注软件体系结构的结构化特性, 将系统(本身也是一个复合构件) 描述为构件和连接子的配置, 其中构件表示计算或者数据, 而连接子表示构件之间的交互. 每个构件的接口都对外提供一些演员(player).构件通过这些演员与外界发生交互. 与构件类似, 一个连接子的协议对外提供一些角色(role),连接子通过这些角色来调解构件之间的交互. 图 - 1是用UniCon 的图形化编辑器生成的示意图.

UniCon 概念的示意图

图 - 1中有两个构件, 构件A 和构件B, 它们都是Unix 中的过滤器. 这两个构件都有三个演员, 用三角形表示. 左边的演员表示输入流"standard in",右边的演员是输出流"standard our"和"standard error".两个构件之间是一个连接子, 它是Unix 下的管道. 这个连接子有两个角色:悬垂在左边的表示管道的入口(source),右边的表示管道的出口(sink).

在上图中, 构件和连接子之间还没有交互. 为了在构件之间建立连接, 演员必须和某个角色关联起来. 如图 - 2所示.

在UniCon 建立连接

通过演员与角色的关联, 最终就可以建立整个系统各个部分之间的配置. 最新版本的UniCon 不仅支持类似于上例的管道-过滤器系统, 还支持使用过程调用和共享数据的模块交互系统, 基于RPC 调用的分布式系统, 根据各种实时要求共享处理器的进程以及基于SQL 命令的数据库访问.

UniCon 的提出是为了达到如下目的:

解决系统描述和组装的实际问题, 为实际工具提供一个原型;

为各种连接机制提供一个一致的访问方式

帮助软件设计师区分不同的构件类型和连接子类型并验证构件和连接子配置的正确性

支持图形化和文本化符号以及二者之间的互换

兼容现存的用常见的编程语言编写的构件(这些构件并不需要特定于UniCon) 尽可能的将运行时开销降到最低

以下将具体介绍UniCon 中构件和连接子的定义.

UniCon 中的构件

UniCon 中的构件定义包括规约部分和实现部分.

构件的规约称为构件的接口(interface).接口定义了构件所能进行的计算以及使用构件必须遵循的约束. 构件的接口包含三类信息:

构件类型:构件类型表示构件提供的功能的类型, 它限制了该构件所能定义的演员的数量, 类型和规约.

特性:由属性和值组成的二元组, 用于指定与构件整体相关的附加信息, 例如断言, 约束等.

演员:从构件外部可见的语义单元, 构件通过演员与其它构件发生交互. 其语法如下:

构件的实现有两种形式:

原子(primitive)实现:原子实现是一个指向存在于UniCon 语言外部的文档链接, 该文档包含了相应的构件实现. 它可能是某种编程语言的源代码(目前UniCon 工具集仅仅支持C 语言的源代码), 也可以是目标码, 或者是包含目标码的Unix 档案库文件, 或者是二进制可执行文件,shell 脚本, 数据文件,C 语言的include 文件等 复合(composite)实现:某个UniCon 构件的复合实现是对其它已定义的构件和连接子的配置的描述, 该实现包含三类信息:

片段(piece):用于构造某个配置的构件和连接子实例

配置信息:描述构件和连接子的关联

抽象信息:描述该构件的接口如何由其复合实现中的构件接口实现.

构件实现的语法如下:

UniCon 中的连接子

连接子的定义也包含规约和实现两个部分, 其中规约部分通过协议(protocol)进

行描述. 连接子的协议定义了构件之间允许产生的交互, 并确保这些交互能够顺利进行. 连接子的协议包含三类信息:

连接子类型:连接子类型表示连接子所能调解的构件之间的交互类型, 它限制了连接子的角色的数量, 类型和规约.

特性:由属性和值组成的二元组, 用于指定和连接子整体相关的附加信息, 例如断言, 约束等(例如和时间和顺序相关的规则)

角色:从连接子外部可见的语义单元, 通过角色连接子对构件的交互进行调解. 角色通过与演员发生关联, 从而形成系统的连接, 它定义了参与连接的演员的需求与责任.

连接子的实现是UniCon 内置的, 即UniCon 只支持连接子的原子实现, 它本身不提供用户自定义连接子实现的机制.

连接子的定义的语法如下(从中也可以看出UniCon 目前支持的连接子实现的类型):

UniCon 是最早的体系结构描述语言之一. 从上述介绍可以看出,UniCon 强调将系统划分为构件后, 用适当的连接子将其组装起来构成一个完整的系统. 构件和连接子之间是松耦合关系.UniCon 备受诟病的一点是它只支持预定义的连接子, 并且不支持复合连接子. 为了解决这个问题, 相关研究人员在UniCon 的基础上对其进行了增强. 增强后的UniCon 称为UniCon-2.UniCon-2提供了一个比较灵活的类型系统, 并且引入了责任(duty)这个概念用于描述演员, 角色等与属性的关系. 某个系统配置的责任还可以用于描述体系结构风格. 由于UniCon-2允许用户引入新类型, 为了便于对与新类型相关的约束进行检查,UniCon-2采用了一种开放的编译器结构以便于增加相应的检测方法.

Darwin

Darwin 简介

Darwin 最初是一个分布式系统配置语言, 引入软件体系结构研究后,Darwin 成为一个体系结构描述语言. 作为一个ADL ,Darwin 对软件系统的静态结构的描述和UniCon 非常相似, 不过Darwin 中引入了一些特有的构造(construct)使之便于描述系统的动态特性. 此外,Darwin 使用π演算作为其形式化基础, 因此使用Darwin 描述的体系结构模型能够进行一些高层的模型检测, 例如是否存在死锁等.

Darwin 的建模能力和特点

使用Darwin 描述的软件系统配置主要由构件及构件之间的绑定(binding)组成. Darwin 中的构件是用服务(service)进行定义的, 一个构件既能对外提供一些服务, 也能请求外部的服务. 所有的服务名的作用范围仅限于定义这些服务的构件, 亦即构件的定义本身并不需要了解全局的服务名. 因此Darwin 中的构件是上下文独立的(context independent),这有助于构件的复用, 并能简化维护阶段对构件的替换工作. 构件的服务由服务类型进行区分, 但是Darwin 本身并不解释服务类型信息. 服务类型信息要么由低层的形式化行为规约进行解释, 要么用于表示底层分布式平台所支持的通信机制(例如在Regis 系统中, 类型信息就可以直接用于选择正确的通信代码). 图 - 3是一个过滤器构件的定义, 其中服务的类型信息就是尖括号内的内容.

Darwin 中的构件

Darwin 中的绑定就是构件的provide 服务和require 服务之间的链接. 只有provide 服务类型和require 服务类型相互匹配, 相应的绑定才是合法的. 由于

Darwin 本身只管理服务类型, 并不对其进行解释, 因此必须由提供服务类型的系统来判断服务是否匹配(不过在Darwin 目前的工具集中, 仅仅简单的通过名字是否相同来判断服务是否匹配). 为了灵活的对构件进行绑定,Darwin 中提供了一些特有的关键字, 例如forall,when 等. 下述代码是图 - 4例子的Darwin 描述, 其中流水线的长度是由其参数动态决定的,forall,when 等也体现了Darwin 这种ADL 对动态性的支持.

Darwin 对动态结构的支持主要来自于延迟实例化(lazy instantiation)和 直接动态实例化(direct dynamic instantiation)这两种技术. 延迟实例化是指只有当用户试图访问某个服务时, 提供该服务的构件才被实例化. 将延迟实例化与递归结合起来就能描述几乎不受限制的结构, 其局限性是不能描述循环绑定的结构. 直接动态实例化则允许系统结构随意的发生演化, 这需要底层π演算的相关支持. 具体细节以及与π演算相关的内容请参看相关文献.

可变长度的流水线(Pipeline)

用Darwin 描述的客户服务期系统

使用构件和绑定就能定义Darwin 中的复合构件以及一个系统. 事实上,Darwin 描述的系统就是一个层次式结构化的复合构件. 下述代码就是图 - 5所示的客户服务器系统的Darwin 描述. 注意:其中的System 构件就是最终的系统.

Darwin 的设计面向的是分布式软件, 因此它对系统动态性的支持可以说是天生的. 从抽象的角度来看,Darwin 中的构件及其之间的绑定其实独立于具体的构件交互机制, 因此理论上Darwin 也能用于描述传统的程序结构.

虽然Darwin 能很好的描述系统的动态特性, 但是Darwin 中并没有显式的连接子概念, 因此使用Darwin 进行复杂系统设计时关注的主要还是构件; 当然这似乎并

不会削弱其表达能力. C2 SADL

C2 SADL是UCI 设计的一种基于消息传递的体系结构描述语言, 主要用于描述符合C2风格的软件系统的体系结构.

C2风格

C2风格是一种基于构件和消息的体系结构风格, 主要是应用于带有图形用户接口(GUI)的应用系统, 但也能用于其它类型的应用. 这种风格要求构件之间通过消息交换进行通信. 因此每个C2构件和C2连接子都有一个top 接口和一个

bottom 接口, 其中top 接口定义了该构件所能接收的应答消息和向上发出的请求消息, 而bottom 接口定义了该构件能够进行应答的请求消息及其向下发出的应答. 所有消息都以连接子为桥梁在构件之间进行传递. 这种风格的体系结构将系统中的构件用连接子划分为不同层次, 如图 - 4所示.

C2风格的体系结构:可视化堆栈(Stack)

C2概念的图例

C2风格的核心在于构件之间的" 有限可见性", 即处于系统中某个层次的构件只能" 看到" 上层的构件, 而不清楚下层到底是什么构件在与之进行通信. 具体表现在如下所述的构件之间的通信规则(即系统的组装规则):

构件的top 接口只可能与某一个连接子的bottom 接口相连

构件的bottom 接口只可能与某一个连接子的top 接口相连

与连接子相连的构件或者连接子没有数量限制

两个连接子相连时, 只能是其中一个的bottom 接口与另一个的top 接口相连 C2 SADL

C2 SADL目前还只是一个原型语言, 其相应的支撑工具还在开发中. 该语言包含三个部分:

接口定义符号(IDN, interface definition notation):是C2中的构件接口的规约. 如下所示是一个堆栈(Stack)构件的C2 IDN.

体系结构描述符号(ADN,architecture description notation):是C2体系结构的声明性规约. 例如图 - 4所示例子的相应描述如下:

体系结构构造符号(ACN,architecture construction notation):主要用于表达体系结构的动态变化, 例如如果要在运行时删除堆栈的一种可视化表示方式, 可以用ACN 进行如下描述:

C2 SADL中的连接子本质上是一种消息总线, 复合这种结构的应用系统往往具有比较良好的灵活性和可扩展性. 不过由于C2 SADL还没有针对大型实际系统进行建模和使用, 因此对使用该结构所可能导致的性能问题还不是很明确.

Acme

Acme 简介

Acme 是CMU 的Acme 项目的产物. 该项目始于1995年, 目的是为了研究一个公共的语言, 使之能在不同的体系结构设计工具之间作为体系结构描述信息互换的桥梁. 目前Acme 及其开发工具包AcmeLib 提供了一个通用的, 可扩展的基础框架用于描述, 表示, 生成以及分析系统的软件体系结构. 而作为桥梁作用的Acme, 由于必须具备大多数ADL 共有的概念, 因此它本身也是一个ADL , 并且是一个相对而言比较简单的通用的ADL .

Acme 的建模元素和特点

Acme 的主要特点表现为:

采用七个基本的体系结构设计元素作为体系结构的本体(architectural ontology), 如图 - 6,图 - 7所示.

采用灵活的标注机制支持使用外部语言定义的非结构化信息

使用类型机制对常见的可复用的软件体系结构俗语和风格进行抽象描述 使用开放的语义框架对体系结构描述进行推理

Acme 的设计元素

Acme 的设计元素

以下对Acme 所采用的设计元素进行简要介绍. 这七个设计元素是:

构件(components):系统中的计算元素和数据存储. 直观的说, 就是线框图中的框. 典型的构件有:客户端, 服务器, 数据库, 黑板, 过滤器等.

连接子(connectors):构件之间的交互. 直观的说, 就是线框图中的线. 典型的连接子有:过程调用, 事件广播, 客户和服务器之间的协议等.

系统(systems):构件和连接子的配置.

端口(ports):构件通过端口与外界发生交互. 一个构件可以有多个不同类型的端口, 每个端口都是一个接口的集合, 例如一系列需要以特定顺序调用的过程.

角色(roles):连接子通过角色与外界发生交互. 角色定义了构件之间交互的参与者. 表示(representations):构件或者连接子内部结构的描述. 通过" 表示" 这个概念, 系统的体系结构就具有了层次结构. 同时," 表示" 这个概念可以用于描述体系结构实体的多个视图(但是Acme 本身并不处理视图之间的对应关系), 如图 - 7所示. 表示的映射(rep-maps):将构件或者连接子的内部" 表示" 与外部接口进行映射. 简单的客户端-服务器系统

以下是一个简单的客户端-服务器系统(图 - 8)的Acme 描述.

Acme 本质上是一些ADL 的建模元素的" 最大公约数", 因此它能作为不同ADL 及其支撑工具之间用于信息交换的语言. 这是Acme 的最大作用, 当然这也使得它只能成为一个建模能力一般的ADL , 例如Acme 中就没有相应的机制用于对构件或者系统行为进行描述或者规约. 相关研究者正在考虑在Acme 中引入类似于Wright 中使用的CSP 的形式化语言来解决这个问题. 当然, 作为一个通用的交换语言,Acme 的能力及其可扩展性也不是无限的. 例如Acme 的扩展仅限于在七个基本设计元素的基础上进行, 并且Acme 中缺乏用于描述属性及其数据格式的元语言. 无论如何,Acme 是第一个ADL 之间的互交换语言, 它的出现使得不同的ADL 支持工具之间有可能进行体系结构描述信息的交流.

xADL

xADL 简介

xADL 是UCI 设计的一个基于xml 的ADL , 最新版本是xADL2.0. 其建模元素都是使用xml schema进行定义的.xADL 除了提供ADL 中常见的建模元素外, 还对产品家族的描述提供了一些支持, 例如体系结构版本等. 这是xADL 的一个独特之处. 此外,xADL 本身设计成一个模块化语言, 因此具有良好的可扩展性. xADL 建模元素和特点

作为一个ADL ,xADL 也定义了常见ADL 中的建模元素, 包括构件, 连接子, 构件的接口, 配置等, 其中构件和连接子都具有内部结构. 由于xADL 的模块化特性, 使得用xADL 描述的体系结构看起来就像是一些相互独立的结构的集合. 例如下述代码就是用xADL 描述的一个客户-服务器结构(图 - 11)(由于空间有限, 下述简写代码没有遵循xml 的格式!)

用xADL 描述的客户-服务器系统

除了上述常见的体系结构建模元素,xADL 还提供了一些特有的建模元素用于支持产品家族的建模, 这些元素包括:

选项(Option):允许体系结构描述中的一些构件或者连接子在某些情况下是可选的, 即不一定存在.

变体(Variant):类似于编程语言中的联合(Union).将某些构件或者连接子指定为变体, 意味着这些元素在某些情况下可以被实例化为不同类型的元素.

版本(Version):用于描述构件, 连接子和接口的版本树. 这样就可以在同一个体系结构模型中使用同一类型元素的不同版本.

结构差异(Structural Differing):用于描述两个xADL 结构的差异.

产品线体系结构差异(Product-Line Architecture Differing):用于描述产品线中两个体系结构的差异.

上述建模元素在xADL 中根据抽象层次分为两类, 一类是运行时概念, 包括构件实例, 连接子实例, 接口实例, 链接实例等; 还有一类是运行时概念, 包括构件, 连接子, 接口, 链接等(这些都是类型的概念)

xADL 的另一个特点在于其灵活的可扩展性. 其可扩展性本质上来源于xml 以及schema 的可扩展性, 例如可以通过schema 的include 机制来实现继承等. 当然, 从上述介绍中也可以看出,xADL 也提供了体系结构建模的基本元素, 并且用于定义xADL 的xml schema是独立于其它ADL 的, 因此xADL 也可以用于ADL 之间的转换. 已有研究人员已经给出了从C2,Acme 等ADL 到xADL 的映射规则. xADL 相比UniCon 等ADL 来说属于第二代的ADL . 其xml 基础使其具有良好的可扩展性, 并且由于xml 格式文本的易交换性使得xADL 能比较容易的集成不同的支持工具. 但是由于xml 格式的冗长, 因此对xADL 的使用需要有一定的工具

支持.

体系结构描述语言分类框架

根据对ADL 的研究,Medvidovic 和 Taylor 于2000年提出了一个用于对ADL 进行分类和比较的一般框架, 如表1所示. 该框架认为一个ADL 必须明确的对构件, 连接子和它们的配置进行建模; 为了保证体系结构描述有明确的语义还必须对构件的接口进行建模. 此外, 为了保证可用性和有用性, 它也必须为基于体系结构的开发和演化提供工具支持. 除了上述必需的建模元素外, 不同的方法由于关注点的不同, 可能会关注不同的体系结构特性, 比如系统组装的风格, 某个应用领域的特征以及分布, 并发, 安全和吞吐量等属性.

体系结构描述语言

体系结构建模特性

构件

接口, 类型, 语义, 约束, 演化, 非功能属性

连接子

接口, 类型, 语义, 约束, 演化, 非功能属性

体系结构配置

易理解性, 组装性, 精化和追踪性, 异构性, 可量测性, 演化, 动态性, 约束, 非功能属性 工具支持

主动规约, 多视图, 分析, 精化, 实现生成, 动态性

ADL 的分类与比较框架, 黑体字表示必须建模的元素

如上所述, 构成体系结构描述的三要素是:构件, 连接子和体系结构配置. 因此, 一个ADL 应该提供至少这三种元素的显式描述. 是否同时描述了这三种元素, 也可以

作为判断一个描述语言是否是一个体系结构描述语言的依据. 为了能够对体系结构的一些信息进行推理, 也要求ADL 能够对构成体系结构的构件的接口进行建模, 如果没有接口的描述, 体系结构描述就和线框图没有什么本质区别. 关于构件, 连接子, 配置的其它一些相关方面的描述, 如果有则更好, 但是如果没有提供, 也不表示这个语言不是ADL , 也即这些方面不是判断一个语言是否ADL 的关键标准. 以下分别就该分类框架中对三要素和工具支持方面的要求进行详细介绍, 最后我们给出使用该分类框架对ADL 进行分类和比较的结果.

对构件进行建模

在体系结构中, 构件是系统中的功能单元或数据存储单元. 构件可以小到一个函数, 大到整个系统. 一个构件即可以要求自己拥有独立的数据或运行空间, 也可以和其它构件共享. ADL 用来描述构件的特征如下:接口; 类型; 语义; 约束; 演化; 非功能属性. 下面分别做一些讨论.

接口. 构件的接口是构件和外界环境进行交互的交互点的集合, 指定了一个构件向外界提供的服务(消息, 操作和变量). 为了协助构件和包含该构件的体系结构进行推理, ADL 还应该提供描述构件需求的能力, 即该构件向外界提供功能的同时, 需要外界对它提供那些服务. 这样, 接口就区分成为两种, 一种是构件的对外接口, 一种是构件需求外界提供服务的接口. 简单地说, 接口定义了计算的合约和使用服务的约束.

类型. 构件类型是封装了可复用功能的抽象. 一个构件类型可以多次实例化, 在一个体系结构中多次使用或跨越不同的体系结构使用. 构件类型可以参数化, 使得其具有更强的可复用性. 因为构件类型刻画了其所有实例所共有的属性和特征, 因此可以协助体系结构的理解和分析.

语义. 构件的语义是指其行为的高层模型. 这样的模型可以用来进行分析, 加强体系结构约束和保证体系结构从一个抽象层次向另一个抽象层次映射时的一致性. 约束. 约束是指关于系统或系统的一部分的属性或断言, 对该属性或断言的违背将使得系统不可接受或至少降低了其满意度. 为了使得构件的使用达到预期的效果, 限制构件使用的范围以及建立构件内部成分之间依赖, 对构件的约束必须被指定. 演化. 作为体系建构的重要部分, 构件在进行着不断地演化. 构件的演化可以简单地认为是对构件某些特征, 如接口, 行为或实现, 的修改. ADL 可以通过采用子类型化或精化等手段来使得构件的演化以一种系统化的方式进行.

非功能属性. 一个构件的非功能属性(如安全, 性能, 易移植性等) 不能从其行为中直接导出. 这些属性的早期指定(在体系结构层次), 是使得运行时刻行为的模拟, 性能分析, 加强约束, 构件实现到处理器的映射以及协助项目管理所必须的. 对连接子进行建模

连接子是体系结构中对构件之间的交互和管理这些交互的规则进行建模的重要元素. 与构件不同, 连接子在实现系统中可能并没有实现体与之对应, 它们可能被实现为消息路由, 但是也可能仅仅是共享变量, 数据库表项, 缓冲, 对连接器的指定, 动态数据结构, 初始参数, 客户服务器协议, 内嵌在代码中的过程调用序列等等. 刻画连接子的特征有:接口; 类型; 语义; 约束; 演化; 非功能属性.

接口. 连接子的接口是连接子和与之连接的构件或其它连接子进行交互的交互点集合. 连接子本身不提供任何特定应用的计算, 它只是将与之连接的构件的功能导出给其它构件. 连接子的接口使得构件之间能够正确连接和交互, 从而, 对于体系结构配置的推理起到重要的辅助作用.

类型. 连接子类型是封装了构件通信, 协调和仲裁策略的抽象. 体系结构层次的交

互可能是很复杂的协议, 使得这些复杂的协议能够在体系结构中或跨体系结构复用, 需要ADL 提供将连接子描述为类型的能力. 这通常可以使用两种方式实现, 一是作为可扩展的类型系统, 按照交互协议来定义, 二是作为内嵌的枚举类型, 基于特殊的实现机制.

语义. 与构件的语义相类似, 连接子的语义是连接子行为的高层模型. 但是与构件也有区别. 构件的语义表达了特定应用的功能, 而连接子语义则承担了对(与计算无关的) 交互协议的规约. ADL 应该支持连接子语义的建模, 因为这样可以使得能够对构件的交互进行分析, 保证不同抽象层次的体系结构的精化的一致性, 还可以强化连接和通信的约束.

约束. 连接子约束保证了交互协议的使用达到了预期的目的, 建立了连接子内部的依赖关系, 并强化了使用界限. 一个即简单又能说明约束问题的例子是, 限制能够和一个连接子建立连接并通过该连接子进行交互的构件的数量. 要保证复杂的连接子约束(如最小吞吐量), 可能需要该连接子外部的信息, 如与该连接子连接的构件的动态语义的模型.

演化. 与构件的演化相类似, 连接的演化是指对连接子的特征, 如接口, 语义或约束的修改. 体系结构中构件的交互往往是使用的复杂并且会发生变化和扩展的协议, 而构件和配置也在不断的演化中. ADL 应该能够包容这些演化, 通过对已有连接子进行修改或精化, 修改或精化可以采用诸如增量信息过滤技术, 子类型化和精化等技术.

非功能属性. 连接子的非功能属性不能完全从它的语义规约中得到. 非功能属性是指连接子正确实现所必须满足的(额外) 需求. 对连接子的非功能属性进行建模, 可以在设计阶段对连接子的运行时刻行为做模拟, 对连接子进行分析, 加强约束, 以

及便于从产品化连接子(如消息总线) 的正确挑选.

对配置进行建模

体系结构配置, 或称拓扑结构, 是由描述系统结构的构件和连接子连接而成的图. 体系结构配置信息具有重要的意义, 它可以确定构件是否被正确地连接, 它们的接口是否匹配, 连接这些构件的连接子是否实现了正确的通信, 构件和连接子组合在一起的语义是否符合所希望的行为等. 和构件和连接子模型一起, 配置的描述使得可以对体系结构的并发和分布方面的性质进行评估, 如评估是否存在死锁, 性能, 可靠性, 安全性如何等等. 配置的描述也为分析一个体系结构是否符合设计理念(如构件的直接连接将降低体系结构的演化能力) 和是否满足体系结构风格约束(如构件之间的直接通信连接是被禁止的) 提供帮助.

体系结构配置的特征可以分为以下的三个类别:

配置描述的性质, 包括易理解性, 可组装性, 可精化和追踪性以及异构性. 被描述系统的性质, 包括异构性, 伸缩性, 演化性和动态性.

被描述系统的特性, 包括动态性, 约束和非功能属性.

上述的三个类别并不是正交的, 异构性和动态性出现在两个类别中. 异构性可能在配置描述中采用的多种形式化和在系统实现中采用的多种程序语言中表现出来. 可以预知的动态性是系统的一个属性, 这个属性指的是系统通过特殊的体系结构设计来包容这些(可预测) 的动态变化; 不可预知的动态性是系统的一个性质, 即系统面对动态变化所展现出的适应能力.

易理解性. 软件体系结构的一个重要角色就是作为项目中不同人员之间进行交流的媒介, 使得在一个高的抽象层次上的系统(或系统家族) 的理解更容易. 这样, 就要求ADL 必须以一种简单且易于理解的语法来对结构(或拓扑) 信息进行建模. 并且,

理想的情况是, 不需要对构件和连接子的模型规约进行仔细研究, 就可以比较清楚地理解体系结构的配置规约.

可组装性. 可组装性, 或称层次化组装, 是允许体系结构以不同的细节层次描述软件系统的机制. 如, 复杂的结构或行为可以显式地表示出来, 也可以将它们抽象为一个简单构件或连接子; 一个完整的体系结构可以成为另外一个更大的体系结构中某个构件的内部结构. 这种抽象机制应该作为ADL 建模能力的一部分.

可精化和追踪性. 除了为架构师提供丰富语义精致的设施来指定体系结构外, ADL 还必须提供能够让体系结构正确地精化为可运行系统, 并且能够在不同层次的体系结构精化之间保持追踪性的能力. 这正是ADL 能够出现并得以发展的一个重要原因:在非形式化的" 线框图" 和程序语言之间建立桥梁, 因为程序语言对于设计来说, 抽象层次太低了.

异构性. 体系结构的一个目标便于大型系统的开发, 更可取的是利用已有的不同粒度, 可能使用不同的形式语言定义, 使用不同的编程语言实现, 拥有不同的操作系统需求, 支持不同的通信协议的构件和连接子来设计. 这要求ADL 必须是开放的, 也就是说, ADL 应该提供一些设计和机制, 使得能够使用异构的构件和连接子来进行体系结构的规约和开发. 也就是要求ADL 支持异构的构件和连接子可以在一个体系结构中共同完成系统的设计.

伸缩性. 体系结构的目的就是能够为开发者提供用来解决系统的复杂性和大规模问题的. 从而, ADL 必须能够直接支持大型系统的规约和开发, 并且这样的系统有可能变得更大.

演化性. 一个新的软件系统不可能将所有不可预测的功能也包含进去, 而是采用某种演化方式. 一个体系结构的演化反映了一个软件系统家族的演化, 也使得这种演

化变成可能. 演化(即维护) 是软件开发最昂贵的活动, 因此系统演化性成为基于体系结构开发的关键方面. ADL 需要在构件和连接子的级别增强演化的支持, 允许构件和连接子的增量添加, 删除, 替换, 以及在配置中重新连接.

动态性. 演化多是指的" 离线" 对体系结构(以及目标系统) 的修改, 而动态性是指的在系统运行过程中对系统的体系结构进行修改并影响运行系统. 对动态性的支持对于那些关键系统, 如航空控制, 交换机等, 是非常重要的, 如果为了升级这些系统必须关闭这些系统才能进行, 那将造成极大的损失. 为了支持基于体系结构的运行时刻演化, ADL 需要提供特别的描述能力来对动态变化进行建模, 提供特别的技术能够在运行系统中实现这些变化.

约束. 体系结构级的约束描述了一个配置中的依赖关系. 这些约束是对单个构件和连接子的约束的补充. 很多体系结构级全局约束是直接从一些局部的约束导出的, 或者间接地依赖这些局部约束. 例如, 配置的约束可能通过组成这个配置的构件和连接子的交互约束来表达, 而这些约束又可能用它们的接口和协议来表达. 通过配置来表达的系统性能将以来每一个单独的体系结构元素. 体系结构级的安全也是它的组成部分安全的责任.

非功能属性. 某些非功能属性是系统级的, 而不是单个的构件或连接子的. 配置级非功能属性对于选择正确的构件和连接子, 执行分析, 强化约束, 映射体系结构构造元素到处理单元以及协助项目管理是必须的.

体系结构描述的工具支持

开发形式化语言作为体系结构描述背后的动机, 是因为形式化语言适合被软件工具用来进行推理和操纵. 尽管工具支持并不能算是体系结构描述语言的一部分, 但是体系结构描述语言的可用性与提供一个支持体系结构设计, 分析, 演化甚至可执

行系统的生成等等能力的工具是息息相关的. 体系结构描述语言工具支持的重要性已经被研究人员所重视. 当前体系结构描述语言所能提供的工具支持的功能大致可以分为如下几种:主动规约, 多视图, 分析, 精化, 实现生成和动态性.

主动规约. ADL 工具根据当前体系结构的状态缩小设计的可选择范围, 提供主动的规约支持. 这样的工具提供了设计指导, 极大地降低了体系结构设计人员的认知负荷. 这种支持可以是前摄式的, 建议一些活动的执行过程或禁止一些可能引起不希望出现的状态的设计选择; 也可以是反应式的, 当出现了不希望的状态时, 提醒设计人员. 这种支持可以是强制性的, 要求出现不希望的状态时, 设计人员必须马上处理, 否则将不能进行下去; 也可以是非强制性的, 设计人员可以在适当的时候进行处理.

多视图. 在设计体系结构时, 不同的人员(如架构师, 开发人员, 管理人员, 客户等) 可能要求体系结构的不同视图. 为客户提供一个简单的, 高抽象层次的" 线框图" 可能就使他们满意, 但是开发人员可能需要详细的(甚至形式化的) 构件和连接子规约, 而管理人员可以需要与系统开发过程相关的视图来更好地完成项目的管理. 为特定的人员提供特定的视图, 并且能够保证视图之间的一致性, 是ADL 工具需要关注的重要问题.

分析. 体系结构描述经常被用来对大型分布式并发系统进行建模. 对这些系统的一些属性, 在体系结构这样一个较高抽象层次上进行评估的能力, 可以大大地缩小错误所带来的开销. 并且体系结构描述是大粒度的抽象, 屏蔽了很多细节, 使得对体系结构级的分析比对代码级的分析容易. 从而, 体系结构分析成为ADL 工具开发者的一个主要关注点.

精化. 不少文献对支持体系结构的精化做了简要探讨, 认为在不同的体系结构细节

层次间的精化支持是非常重要的. 对体系结构描述的精化是一项复杂的任务, 其正确性和一致性不能完全地依靠形式化证明来保证, 足够的工具支持可以给设计人员在这方面增加一些自信.

实现生成. 任何软件设计和建模的努力其最终目标是产生一个可执行系统. 一个设计优美的体系结构模型如果不能够转换到运行系统, 就没有太大的价值. 通过手工的方式将体系结构转换到运行系统很导致很多一致性和追踪性方面的问题, 从而, ADL 工具能够提供代码生成的支持将是非常有意义的.

动态性. 前面已经讨论了在体系结构层次对动态变化进行建模的必要性. 但

是, ADL 只是具有对动态变化建模的能力是不够的, 不能保证这些变化能够以一种正确的方式被应用到运行系统中. 这要求提供工具的支持, 用来分析被修改的体系结构, 保证其中的一些重要特性, 将使用体系结构元素描述的变化映射到运行系统的模块上, 同时保证系统关键模块的不间断运行, 在修改过程中保持系统的状态, 并能够分析和测试正在运行的系统.

比较结果

根据该分类框架, 我们选取上述ADL (UniCon,Darwin,C2 SADL,Acme,xADL)进行比较.

从整体上看, 参与比较的所有ADL 都提供了对构件建模的全面支持, 所有的ADL 都将构件作为一阶实体, 区分构件类型和实例, 并且都对接口建模提供了支持. 但是, 这些ADL 都不支持演化和非功能属性.

在对连接子进行建模方面, 有Darwin 没有将连接子作为一阶实体来看待; 但是所有对连接子进行显式建模的ADL 都提供了对连接子接口的建模, 并区分连接子类型和实例.

在对配置进行建模方面, 尽管不同的体系结构描述语言中提供的构件和连接子的能力各不相同, 但是所有体系结构描述语言都能描述系统的拓扑结构; 至于演化性, 动态性等方面的支持, 不同语言的支持程度各有不同.

以上是对上述ADL 对构件建模和连接子建模的支持的简要比较, 详细的比较结果请参看表 - 2,表 - 3和表 - 4.

体系结构描述语言的构件建模能力比较

UniCon

Darwin

C2 SADL

ACME

xADL

特性

构件, 实现独立

构件, 实现独立

构件, 实现独立

构件, 实现独立

构件, 实现独立

接口

接口用player 进行建模

接口用service 进行建模(区分provided 和required)

接口区分provided 和required, 接口信息通过顶层port 和底层port 输出 用port 建模

接口用interface 进行建模

类型

预定义类型

可扩展类型系统, 支持参数化

可扩展的类型系统

可扩展的类型系统, 通过模板进行参数化

可扩展的类型系统, 可自定义类型

语义

属性列表中的事件踪迹

π演算

用一阶逻辑描述的构件不变量和前置, 后置操作

不支持, 不过能在属性列表中使用其它ADL 的语义模型

不变量和前置, 后置条件

约束

通过接口和语义进行约束; 属性; 对构件类型所能提供的player 进行限制 通过接口和语义进行约束

通过接口和语义进行约束; 风格不变量

仅通过接口进行约束

通过接口和语义进行约束

演化

各种子类型化

使用extends 对结构进行子类型化

支持产品线建模, 版本建模

非功能属性

用于可调度性分析的属性

通过属性列表进行定义, 但不对其进行操作

体系结构描述语言的连接子建模能力比较

UniCon

Darwin

C2 SADL

ACME

xADL

特性

支持显式的连接子

内嵌的绑定; 不对构件交互进行显式建模

支持显式的连接子

支持显式的连接子

支持显式的连接子

接口

用role 进行建模

无; 允许定义" 连接构件"

通过独立的port 与构件进行交互, 接口区分provided 和required 用role 进行建模

用interface 进行建模

类型

预定义连接子类型

基于协议的可扩展类型系统

基于协议的可扩展的类型系统; 使用模板实现参数化

可扩展的类型系统, 可自定义类型

语义

隐含在连接子类型中; 可以使用属性列表定义语义信息

通过消息过滤器支持部分语义

不支持, 但可以在属性列表中使用其它ADL 的语义模型

不变量和前置, 后置条件

约束

通过接口进行约束; 能够限制指定的role 所能连接的player 类型

通过语义进行约束; 风格不变量(每个port 只与一个链接相关)

通过接口和类型对实例进行约束

通过接口和语义进行约束

演化

上下文反射接口; 可演化的过滤机制

通过extends 对结构进行子类型化

支持产品线建模, 版本建模

非功能属性

用于可调度性分析的属性

通过属性列表进行定义, 但是不对其进行操作

体系结构描述语言对配置的建模能力的比较

UniCon

Darwin

C2 SADL

ACME

xADL

特性

使用显式的连接子来描述配置

内嵌的绑定

显式的体系结构拓扑结构

显式的attachment

使用显式的连接子来描述配置

易理解性

显式的文本和图形化规约; 配置描述可以是分布式的

许多连接子细节体现在内嵌的文本规约中; 提供了图形化符号

显式的精确的文本与图形化规约

显式的精确的文本规约

显式的精确的文本规约

组装性

通过复合构件和连接子实现组装

通过其语言中的复合构件实现组装

支持组装; 通过内部构件的体系结构加以支持

模版, 表示层以及表示层映射

通过复合构件和连接子实现组装

精化/易追踪性

支持系统生成; 对实现有所限制

对实现进行限制后能支持系统生成

表示层映射

支持系统生成; 有一定的工具支持

异构性

仅支持预定义的构件和连接子类型; 支持构件的包装

允许用多种语言对原子构件的语义进行建模; 支持C++开发

通过内部构件的体系结构加以支持; 支持Java,C++和Ada 的开发

开放的属性列表; 需要显式的ADL 之间的映射

支持不同语言的实现体; 实现与规约分离

易伸缩性

受益于显式的配置和可变数目的连接子角色

受制于内嵌的配置

得益于显式的配置和可变的连接子端口; 用于自身工具集的构建

得益于显式的配置; 但受制于固定的角色数量

得益于显式的配置; 使用schema 从而具有schema 的可扩展性

演化性

对体系结构的局部描述提供了部分支持; 受益于显式的配置

不支持体系结构的局部描述; 受制于内嵌的配置

支持体系结构的局部描述; 受益于显式的的配置; 构件间的相互依赖最小化; 异构的连接子

受益于显式的配置; 一阶的家族概念

受益于显式的配置; 支持产品线和版本概念

动态性

有限的动态性; 支持构件的运行时复制和带条件判断的配置

不可预期的动态性; 支持元素的插入, 删除与重新连接

使用variant 支持一定的动态能力

约束

连接子只能和role 相连

Provided 服务只能与required 服务相连

确定的风格不变量

Port 只能与role 相连

构件的interface 只能与连接子的interface 相连

非功能属性

通过属性列表进行定义, 但是不对其进行操作

参考文献

Medvidovic N. and Taylor R., "A Classification and Comparison

Framework for Software Architecture Description Languages", IEEE Transactions on Software Engineering, Vol.26, No.1, 2000

Allen R. and Garlan D., "A formal Basis for Architectural Connection",

ACM Transactions on Software Engineering and Methodology, July, 1997. Luckham D. and Vera J., "An Event-Based Architecture Definition Language", IEEE Transactions on Software Engineering, Sept., 1995.

Shaw M., Deline R., Klein D.V., Ross T.L., Young D.M. and Zelesnik G., "Abstractions for Software Architecture and Tools to Support Them", IEEE Transactions on Software Engineering, April 1995

Garlan D., Monroe R. and Wile D., "Acme: An Architecture Description Interchange Language", In Proceedings of CASCON'97, Nov 1997. Dashofy E., Hoek A., and Taylor R., "A Highly-Extensible, XML-Based Architecture Description Language", In Proceedings of the Working IEEE/IFIP Conference on Software Architectures, 2001.

C. Ghezzi, M. Jazayeri, and D. Mandrioli, Fundamentals of Software Engineering. Prentice Hall, 1991.

M. Shaw and D. Garlan, Formulations and Formalisms in Software Architecture, Computer Science Today: Recent Trends and

Developments. J. van Leeuwen, ed. Springer-Verlag, 1995.

M. Moriconi, X. Qian, and R.A. Riemenschneider, Correct Architecture Refinement, IEEE Trans. Software Eng., vol. 21, no. 4, pp. 356-372, Apr. 1995.

P. Oreizy, N. Medvidovic, and R.N. Taylor, Architecture-Based Runtime Software Evolution, Proc. 20th Int'l Conf. Software Eng. (ICSE '98), pp. 177-186, Apr. 1998.

D. Garlan, J. Ockerbloom, and D. Wile, Towards an ADL Toolkit, EDCS Architecture and Generation Cluster, Dec. 1998.

http://www.cs.cmu.edu/~spok/adl /index.html.

D. Garlan, Style-Based Refinement for Software Architecture, Proc.

Second Int'l Software Architecture Workshop (ISAW-2), A.L. Wolf, ed., pp. 72-75, Oct. 1996.

architecture StackVisualizationArchitecture is

components

top_most StackADT;

internal StackVisualization1; StackVisualization2;

bottom_most GraphicsServer;

connectors

connector TopConnector is

message_filter no_filtering

end TopConnector;

connector BottomConnector is

message_filter no_filtering

end BottomConnector;

architectural_topology

connector TopConnector connections

top_ports StackADT;

bottom_ports StackVisualization1; StackVisualization2;

connector BottomConnector connections

top_ports StackVisualization1; StackVisualization2;

bottom_ports GraphicsServer;

end StackVisualizationArchitecture;

archInstance{

componentInstance{

(attr) id = "client1"

description = "Client"

interfaceInstance{ (attr) id = "client1.IFACE_TOP" …… }

interfaceInstance{ (attr) id = "client1.IFACE_BOTTOM" …… } }

connectorInstance{

(attr) id = "conn1"

description = "Connector"

interfaceInstan ce{ (attr) id = "conn1.IFACE_TOP" …… }

interfaceInstance{ (attr) id = "conn1.IFACE_BOTTOM" …… } }

componentInstance{

(attr) id = "server1"

description = "Server"

interfaceInstance{ (attr) id = "server1.IFACE_TOP" …… }

interfaceInstance{ (attr) id = "server1.IFACE_BOTTOM" …… } }

linkInstance{

(attr) id = "link1"

description = "Comp1 to Conn1 Link"

point{ (link) anchorOnInterface = "#client1.IFACE_BOTTOM" } point{ (link) anchorOnInterface = "#conn1.IFACE_TOP" } }

linkInstance{

(attr) id = "link2"

description = "Conn1 to Comp2 Link"

point{ (link) anchorOnInterface = "#conn1.IFACE_BOTTOM" } point{ (link) anchorOnInterface = "#server1.IFACE_TOP" } }

}

component Server{

provide p;

}

component Client{

require r;

}

component System{

inst

A: Client; B: Server;

bind

A.r – B.p ;

}

component pipeline (int n) {

provide input;

require output;

array F[nl:filter;

forall k:0..n-i {

inst Flk];

bind F[kl.output -- output:

when k

F[k].next -- F[k+ 1].prev;

}

bind

input -- F[O].prev;

F[n-1].next-- output;

}

System simple_cs =

{

Component client = { Port send-request; };

Component server = { Port receive-request; };

Connector rpc = { Roles { caller, callee}};

Attachments {

client.send-request to rpc.caller;

server.receive-request to rpc.callee;

}

StackVisualizationArchitecture.remove(StackVisualization1); StackVisualizationArchitecture.unweld(TopConnector, StackVisualization1);

StackVisualizationArchitecture.unweld(StackVisualization1, BottomConnector);

:==

|

:==

IMPLEMENTATION IS

END IMPLEMENTATION

:== VARIANT IN ""

END

:==

IMPLEMENTATION IS

END IMPLEMENTATION

:==

|

|

|

:==

COMPONENT

END

:==

INTERFACE IS

TYPE

END INTERFACE

:==

Module | Computation | SharedData | SeqFile | Filter | Process

| SchedProcess | General

:==

CONNECTOR

END

:==

PROTOCOL IS

TYPE

END PROTOCOL

:==

DataAccess | FileIO | Pipe | PLBundler

| ProcedureCall | RemoteProcCall | RTScheduler :==

IMPLEMENTATION IS

BUILTIN

END IMPLEMENTATION

软件体系结构描述语言(ADL)

要点浏览

本章将对学术界常见的体系结构描述语言进行介绍. 由于研究流派不同, 各种ADL 的设计和能力也不尽相同. 本章选取五种比较典型的ADL 作为代表, 希望能让读者了解主流ADL 的基本能力, 主要功能和应用范围. 为了让读者对各种ADL 有一个更为清晰的认识, 本章最后还对这五种典型的ADL 进行了比较全面的比较. 通过本章的学习, 您将能:

了解主流ADL 的语法和语义

掌握主流ADL 的特点

区分主流ADL 的不同

总体介绍

任何一个软件系统都有结构, 在系统开发过程中的分析设计阶段, 通过考察系统的结构, 可以对系统的开发和实现提供良好的基础. 系统的结构往往体现为系统的各个部分之间的配置. 对于描述软件系统配置的表示法的研究由来已久. 早在1975年,DeRemer 和Kron 就设计了模块互连语言(Module Interconnection

Language,MIL) 用于描述结构化的基于模块的程序. 在MIL 中, 模块可能需要导入/导出各种资源. 所谓的" 资源" 就是命名元素, 例如类型定义, 常量, 变量, 函数等.MIL 的编译器通过进行模块间的类型检查来保证系统的完整性, 常见的检查包括:某个模块要使用的资源是否已经被其它模块提供了, 资源的类型是否匹配, 一个模块的实现是否确实提供了其规约中声明的资源, 一个模块是否有权访问它要使用的资源等.

早期的MIL 要求不同模块的开发人员在开发前先达成很多一致. 例如:能够根据简单的名字匹配来发现模块之间的交互, 所有的模块都是用同一种语言开发的, 所有的模块在组装系统时都可用, 模块的接口描述了与之进行交互的其它模块……进一步的研究逐步弱化了这些限制. 例如Darwin 允许模块在运行时动态的实例化并进行绑定;Polygen 允许不同的模块用不同的编程语言进行开发. 各种软件配置的表示法逐渐成熟, 它们既能描述静态也能描述动态的结构化的分布式系统. MIL 的关注点是模块及其之间的互连. 随着系统复杂度的提高, 人们发现模块之间的交互逐步变得复杂. 研究人员对模块之间交互的重视导致了" 连接子

"(connector)这个概念的诞生, 它主要用于描述软件系统的各个组成部分

(component)即构件之间的交互关系. 从而软件系统的结构可以自然的用构件, 连接子及其之间的配置进行描述. 将连接子作为与构件同等重要的一阶实体进行处理, 是因为如果不将构件之间的交互显式的进行描述, 将会带来一些问题, 包括: 难以将构件之间的交互信息局部化, 从而导致难以识别系统中的连接, 并且难以复用连接机制

构件之间的关系难以进行抽象, 从而阻碍对整个系统结构的理解

由于构件的实现和交互信息绑定在一起, 对不同构件的使用往往会因为交互机制的不兼容而产生严重的集成问题.

支持构件, 连接子及其配置的描述语言就是如今所说的体系结构描述语言

(Architecture Description Language,ADL ).UniCon 就是最早出现的一种体系结构描述语言. 此外, 典型的ADL 还包括:

Rapide:一种事件驱动的ADL , 它以体系结构定义作为开发框架, 支持基于构件的开发. 该语言提供了建模, 分析, 仿真和代码生成的能力, 但是没有将连接子显式地表示为一阶实体.

Wright:其主要特点是将CSP 用于软件体系结构的描述, 从而完成对体系结构描述的某些形式化推理(包括相容性检查和死锁检查等). 但它仅仅是一个设计规约语言, 只能用于描述, 无法支持系统生成, 同时CSP 的使用也是比较困难的事情. Acme:支持ADL 之间的映射及工具集成的体系结构互交换语言. 其目标是作为体系结构设计的一个共同的互交换格式, 以便将现有的各种ADL 在这个框架下统一起来; 而它本身也可以看作是一种ADL .

xArch:一种基于XML 的ADL . 它使用XML 定义了描述体系结构的核心元素, 可

以用来简单的描述软件体系结构, 也可以作为设计其它ADL 的基础, 或者用作体系结构描述描述语言的互交换机制.

xADL2.0:以xArch 为基础的基于XML 的ADL . 除了xArch 的核心元

素,xADL2.0 还提供了对系统运行时刻和设计时刻的元素的建模支持, 类似版本, 选项和变量等更高级的配置管理观念, 以及对产品家族的体系结构的建模支持. 此外,xADL2.0还利用XML 的可扩展性简化了新的ADL 的设计及其相应工具的开发过程.

各种ADL 的出现为描述软件系统的结构提供了一种形式化的描述方法, 而不是容易引起歧异的线框图. 这种精确的描述也使得设计人员能够在系统开发的早期阶段对系统结构进行高层的分析和验证, 从而有助于提高软件开发质量, 降低开发成本.

以下我们将着重介绍五种ADL :UniCon,Darwin,C2 SADL,Acme和xADL. 常见的体系结构描述语言

UniCon (Universal Connector)

UniCon 简介

UniCon 是由CMU 和SEI 设计的一个体系结构描述语言. 该语言关注软件体系结构的结构化特性, 将系统(本身也是一个复合构件) 描述为构件和连接子的配置, 其中构件表示计算或者数据, 而连接子表示构件之间的交互. 每个构件的接口都对外提供一些演员(player).构件通过这些演员与外界发生交互. 与构件类似, 一个连接子的协议对外提供一些角色(role),连接子通过这些角色来调解构件之间的交互. 图 - 1是用UniCon 的图形化编辑器生成的示意图.

UniCon 概念的示意图

图 - 1中有两个构件, 构件A 和构件B, 它们都是Unix 中的过滤器. 这两个构件都有三个演员, 用三角形表示. 左边的演员表示输入流"standard in",右边的演员是输出流"standard our"和"standard error".两个构件之间是一个连接子, 它是Unix 下的管道. 这个连接子有两个角色:悬垂在左边的表示管道的入口(source),右边的表示管道的出口(sink).

在上图中, 构件和连接子之间还没有交互. 为了在构件之间建立连接, 演员必须和某个角色关联起来. 如图 - 2所示.

在UniCon 建立连接

通过演员与角色的关联, 最终就可以建立整个系统各个部分之间的配置. 最新版本的UniCon 不仅支持类似于上例的管道-过滤器系统, 还支持使用过程调用和共享数据的模块交互系统, 基于RPC 调用的分布式系统, 根据各种实时要求共享处理器的进程以及基于SQL 命令的数据库访问.

UniCon 的提出是为了达到如下目的:

解决系统描述和组装的实际问题, 为实际工具提供一个原型;

为各种连接机制提供一个一致的访问方式

帮助软件设计师区分不同的构件类型和连接子类型并验证构件和连接子配置的正确性

支持图形化和文本化符号以及二者之间的互换

兼容现存的用常见的编程语言编写的构件(这些构件并不需要特定于UniCon) 尽可能的将运行时开销降到最低

以下将具体介绍UniCon 中构件和连接子的定义.

UniCon 中的构件

UniCon 中的构件定义包括规约部分和实现部分.

构件的规约称为构件的接口(interface).接口定义了构件所能进行的计算以及使用构件必须遵循的约束. 构件的接口包含三类信息:

构件类型:构件类型表示构件提供的功能的类型, 它限制了该构件所能定义的演员的数量, 类型和规约.

特性:由属性和值组成的二元组, 用于指定与构件整体相关的附加信息, 例如断言, 约束等.

演员:从构件外部可见的语义单元, 构件通过演员与其它构件发生交互. 其语法如下:

构件的实现有两种形式:

原子(primitive)实现:原子实现是一个指向存在于UniCon 语言外部的文档链接, 该文档包含了相应的构件实现. 它可能是某种编程语言的源代码(目前UniCon 工具集仅仅支持C 语言的源代码), 也可以是目标码, 或者是包含目标码的Unix 档案库文件, 或者是二进制可执行文件,shell 脚本, 数据文件,C 语言的include 文件等 复合(composite)实现:某个UniCon 构件的复合实现是对其它已定义的构件和连接子的配置的描述, 该实现包含三类信息:

片段(piece):用于构造某个配置的构件和连接子实例

配置信息:描述构件和连接子的关联

抽象信息:描述该构件的接口如何由其复合实现中的构件接口实现.

构件实现的语法如下:

UniCon 中的连接子

连接子的定义也包含规约和实现两个部分, 其中规约部分通过协议(protocol)进

行描述. 连接子的协议定义了构件之间允许产生的交互, 并确保这些交互能够顺利进行. 连接子的协议包含三类信息:

连接子类型:连接子类型表示连接子所能调解的构件之间的交互类型, 它限制了连接子的角色的数量, 类型和规约.

特性:由属性和值组成的二元组, 用于指定和连接子整体相关的附加信息, 例如断言, 约束等(例如和时间和顺序相关的规则)

角色:从连接子外部可见的语义单元, 通过角色连接子对构件的交互进行调解. 角色通过与演员发生关联, 从而形成系统的连接, 它定义了参与连接的演员的需求与责任.

连接子的实现是UniCon 内置的, 即UniCon 只支持连接子的原子实现, 它本身不提供用户自定义连接子实现的机制.

连接子的定义的语法如下(从中也可以看出UniCon 目前支持的连接子实现的类型):

UniCon 是最早的体系结构描述语言之一. 从上述介绍可以看出,UniCon 强调将系统划分为构件后, 用适当的连接子将其组装起来构成一个完整的系统. 构件和连接子之间是松耦合关系.UniCon 备受诟病的一点是它只支持预定义的连接子, 并且不支持复合连接子. 为了解决这个问题, 相关研究人员在UniCon 的基础上对其进行了增强. 增强后的UniCon 称为UniCon-2.UniCon-2提供了一个比较灵活的类型系统, 并且引入了责任(duty)这个概念用于描述演员, 角色等与属性的关系. 某个系统配置的责任还可以用于描述体系结构风格. 由于UniCon-2允许用户引入新类型, 为了便于对与新类型相关的约束进行检查,UniCon-2采用了一种开放的编译器结构以便于增加相应的检测方法.

Darwin

Darwin 简介

Darwin 最初是一个分布式系统配置语言, 引入软件体系结构研究后,Darwin 成为一个体系结构描述语言. 作为一个ADL ,Darwin 对软件系统的静态结构的描述和UniCon 非常相似, 不过Darwin 中引入了一些特有的构造(construct)使之便于描述系统的动态特性. 此外,Darwin 使用π演算作为其形式化基础, 因此使用Darwin 描述的体系结构模型能够进行一些高层的模型检测, 例如是否存在死锁等.

Darwin 的建模能力和特点

使用Darwin 描述的软件系统配置主要由构件及构件之间的绑定(binding)组成. Darwin 中的构件是用服务(service)进行定义的, 一个构件既能对外提供一些服务, 也能请求外部的服务. 所有的服务名的作用范围仅限于定义这些服务的构件, 亦即构件的定义本身并不需要了解全局的服务名. 因此Darwin 中的构件是上下文独立的(context independent),这有助于构件的复用, 并能简化维护阶段对构件的替换工作. 构件的服务由服务类型进行区分, 但是Darwin 本身并不解释服务类型信息. 服务类型信息要么由低层的形式化行为规约进行解释, 要么用于表示底层分布式平台所支持的通信机制(例如在Regis 系统中, 类型信息就可以直接用于选择正确的通信代码). 图 - 3是一个过滤器构件的定义, 其中服务的类型信息就是尖括号内的内容.

Darwin 中的构件

Darwin 中的绑定就是构件的provide 服务和require 服务之间的链接. 只有provide 服务类型和require 服务类型相互匹配, 相应的绑定才是合法的. 由于

Darwin 本身只管理服务类型, 并不对其进行解释, 因此必须由提供服务类型的系统来判断服务是否匹配(不过在Darwin 目前的工具集中, 仅仅简单的通过名字是否相同来判断服务是否匹配). 为了灵活的对构件进行绑定,Darwin 中提供了一些特有的关键字, 例如forall,when 等. 下述代码是图 - 4例子的Darwin 描述, 其中流水线的长度是由其参数动态决定的,forall,when 等也体现了Darwin 这种ADL 对动态性的支持.

Darwin 对动态结构的支持主要来自于延迟实例化(lazy instantiation)和 直接动态实例化(direct dynamic instantiation)这两种技术. 延迟实例化是指只有当用户试图访问某个服务时, 提供该服务的构件才被实例化. 将延迟实例化与递归结合起来就能描述几乎不受限制的结构, 其局限性是不能描述循环绑定的结构. 直接动态实例化则允许系统结构随意的发生演化, 这需要底层π演算的相关支持. 具体细节以及与π演算相关的内容请参看相关文献.

可变长度的流水线(Pipeline)

用Darwin 描述的客户服务期系统

使用构件和绑定就能定义Darwin 中的复合构件以及一个系统. 事实上,Darwin 描述的系统就是一个层次式结构化的复合构件. 下述代码就是图 - 5所示的客户服务器系统的Darwin 描述. 注意:其中的System 构件就是最终的系统.

Darwin 的设计面向的是分布式软件, 因此它对系统动态性的支持可以说是天生的. 从抽象的角度来看,Darwin 中的构件及其之间的绑定其实独立于具体的构件交互机制, 因此理论上Darwin 也能用于描述传统的程序结构.

虽然Darwin 能很好的描述系统的动态特性, 但是Darwin 中并没有显式的连接子概念, 因此使用Darwin 进行复杂系统设计时关注的主要还是构件; 当然这似乎并

不会削弱其表达能力. C2 SADL

C2 SADL是UCI 设计的一种基于消息传递的体系结构描述语言, 主要用于描述符合C2风格的软件系统的体系结构.

C2风格

C2风格是一种基于构件和消息的体系结构风格, 主要是应用于带有图形用户接口(GUI)的应用系统, 但也能用于其它类型的应用. 这种风格要求构件之间通过消息交换进行通信. 因此每个C2构件和C2连接子都有一个top 接口和一个

bottom 接口, 其中top 接口定义了该构件所能接收的应答消息和向上发出的请求消息, 而bottom 接口定义了该构件能够进行应答的请求消息及其向下发出的应答. 所有消息都以连接子为桥梁在构件之间进行传递. 这种风格的体系结构将系统中的构件用连接子划分为不同层次, 如图 - 4所示.

C2风格的体系结构:可视化堆栈(Stack)

C2概念的图例

C2风格的核心在于构件之间的" 有限可见性", 即处于系统中某个层次的构件只能" 看到" 上层的构件, 而不清楚下层到底是什么构件在与之进行通信. 具体表现在如下所述的构件之间的通信规则(即系统的组装规则):

构件的top 接口只可能与某一个连接子的bottom 接口相连

构件的bottom 接口只可能与某一个连接子的top 接口相连

与连接子相连的构件或者连接子没有数量限制

两个连接子相连时, 只能是其中一个的bottom 接口与另一个的top 接口相连 C2 SADL

C2 SADL目前还只是一个原型语言, 其相应的支撑工具还在开发中. 该语言包含三个部分:

接口定义符号(IDN, interface definition notation):是C2中的构件接口的规约. 如下所示是一个堆栈(Stack)构件的C2 IDN.

体系结构描述符号(ADN,architecture description notation):是C2体系结构的声明性规约. 例如图 - 4所示例子的相应描述如下:

体系结构构造符号(ACN,architecture construction notation):主要用于表达体系结构的动态变化, 例如如果要在运行时删除堆栈的一种可视化表示方式, 可以用ACN 进行如下描述:

C2 SADL中的连接子本质上是一种消息总线, 复合这种结构的应用系统往往具有比较良好的灵活性和可扩展性. 不过由于C2 SADL还没有针对大型实际系统进行建模和使用, 因此对使用该结构所可能导致的性能问题还不是很明确.

Acme

Acme 简介

Acme 是CMU 的Acme 项目的产物. 该项目始于1995年, 目的是为了研究一个公共的语言, 使之能在不同的体系结构设计工具之间作为体系结构描述信息互换的桥梁. 目前Acme 及其开发工具包AcmeLib 提供了一个通用的, 可扩展的基础框架用于描述, 表示, 生成以及分析系统的软件体系结构. 而作为桥梁作用的Acme, 由于必须具备大多数ADL 共有的概念, 因此它本身也是一个ADL , 并且是一个相对而言比较简单的通用的ADL .

Acme 的建模元素和特点

Acme 的主要特点表现为:

采用七个基本的体系结构设计元素作为体系结构的本体(architectural ontology), 如图 - 6,图 - 7所示.

采用灵活的标注机制支持使用外部语言定义的非结构化信息

使用类型机制对常见的可复用的软件体系结构俗语和风格进行抽象描述 使用开放的语义框架对体系结构描述进行推理

Acme 的设计元素

Acme 的设计元素

以下对Acme 所采用的设计元素进行简要介绍. 这七个设计元素是:

构件(components):系统中的计算元素和数据存储. 直观的说, 就是线框图中的框. 典型的构件有:客户端, 服务器, 数据库, 黑板, 过滤器等.

连接子(connectors):构件之间的交互. 直观的说, 就是线框图中的线. 典型的连接子有:过程调用, 事件广播, 客户和服务器之间的协议等.

系统(systems):构件和连接子的配置.

端口(ports):构件通过端口与外界发生交互. 一个构件可以有多个不同类型的端口, 每个端口都是一个接口的集合, 例如一系列需要以特定顺序调用的过程.

角色(roles):连接子通过角色与外界发生交互. 角色定义了构件之间交互的参与者. 表示(representations):构件或者连接子内部结构的描述. 通过" 表示" 这个概念, 系统的体系结构就具有了层次结构. 同时," 表示" 这个概念可以用于描述体系结构实体的多个视图(但是Acme 本身并不处理视图之间的对应关系), 如图 - 7所示. 表示的映射(rep-maps):将构件或者连接子的内部" 表示" 与外部接口进行映射. 简单的客户端-服务器系统

以下是一个简单的客户端-服务器系统(图 - 8)的Acme 描述.

Acme 本质上是一些ADL 的建模元素的" 最大公约数", 因此它能作为不同ADL 及其支撑工具之间用于信息交换的语言. 这是Acme 的最大作用, 当然这也使得它只能成为一个建模能力一般的ADL , 例如Acme 中就没有相应的机制用于对构件或者系统行为进行描述或者规约. 相关研究者正在考虑在Acme 中引入类似于Wright 中使用的CSP 的形式化语言来解决这个问题. 当然, 作为一个通用的交换语言,Acme 的能力及其可扩展性也不是无限的. 例如Acme 的扩展仅限于在七个基本设计元素的基础上进行, 并且Acme 中缺乏用于描述属性及其数据格式的元语言. 无论如何,Acme 是第一个ADL 之间的互交换语言, 它的出现使得不同的ADL 支持工具之间有可能进行体系结构描述信息的交流.

xADL

xADL 简介

xADL 是UCI 设计的一个基于xml 的ADL , 最新版本是xADL2.0. 其建模元素都是使用xml schema进行定义的.xADL 除了提供ADL 中常见的建模元素外, 还对产品家族的描述提供了一些支持, 例如体系结构版本等. 这是xADL 的一个独特之处. 此外,xADL 本身设计成一个模块化语言, 因此具有良好的可扩展性. xADL 建模元素和特点

作为一个ADL ,xADL 也定义了常见ADL 中的建模元素, 包括构件, 连接子, 构件的接口, 配置等, 其中构件和连接子都具有内部结构. 由于xADL 的模块化特性, 使得用xADL 描述的体系结构看起来就像是一些相互独立的结构的集合. 例如下述代码就是用xADL 描述的一个客户-服务器结构(图 - 11)(由于空间有限, 下述简写代码没有遵循xml 的格式!)

用xADL 描述的客户-服务器系统

除了上述常见的体系结构建模元素,xADL 还提供了一些特有的建模元素用于支持产品家族的建模, 这些元素包括:

选项(Option):允许体系结构描述中的一些构件或者连接子在某些情况下是可选的, 即不一定存在.

变体(Variant):类似于编程语言中的联合(Union).将某些构件或者连接子指定为变体, 意味着这些元素在某些情况下可以被实例化为不同类型的元素.

版本(Version):用于描述构件, 连接子和接口的版本树. 这样就可以在同一个体系结构模型中使用同一类型元素的不同版本.

结构差异(Structural Differing):用于描述两个xADL 结构的差异.

产品线体系结构差异(Product-Line Architecture Differing):用于描述产品线中两个体系结构的差异.

上述建模元素在xADL 中根据抽象层次分为两类, 一类是运行时概念, 包括构件实例, 连接子实例, 接口实例, 链接实例等; 还有一类是运行时概念, 包括构件, 连接子, 接口, 链接等(这些都是类型的概念)

xADL 的另一个特点在于其灵活的可扩展性. 其可扩展性本质上来源于xml 以及schema 的可扩展性, 例如可以通过schema 的include 机制来实现继承等. 当然, 从上述介绍中也可以看出,xADL 也提供了体系结构建模的基本元素, 并且用于定义xADL 的xml schema是独立于其它ADL 的, 因此xADL 也可以用于ADL 之间的转换. 已有研究人员已经给出了从C2,Acme 等ADL 到xADL 的映射规则. xADL 相比UniCon 等ADL 来说属于第二代的ADL . 其xml 基础使其具有良好的可扩展性, 并且由于xml 格式文本的易交换性使得xADL 能比较容易的集成不同的支持工具. 但是由于xml 格式的冗长, 因此对xADL 的使用需要有一定的工具

支持.

体系结构描述语言分类框架

根据对ADL 的研究,Medvidovic 和 Taylor 于2000年提出了一个用于对ADL 进行分类和比较的一般框架, 如表1所示. 该框架认为一个ADL 必须明确的对构件, 连接子和它们的配置进行建模; 为了保证体系结构描述有明确的语义还必须对构件的接口进行建模. 此外, 为了保证可用性和有用性, 它也必须为基于体系结构的开发和演化提供工具支持. 除了上述必需的建模元素外, 不同的方法由于关注点的不同, 可能会关注不同的体系结构特性, 比如系统组装的风格, 某个应用领域的特征以及分布, 并发, 安全和吞吐量等属性.

体系结构描述语言

体系结构建模特性

构件

接口, 类型, 语义, 约束, 演化, 非功能属性

连接子

接口, 类型, 语义, 约束, 演化, 非功能属性

体系结构配置

易理解性, 组装性, 精化和追踪性, 异构性, 可量测性, 演化, 动态性, 约束, 非功能属性 工具支持

主动规约, 多视图, 分析, 精化, 实现生成, 动态性

ADL 的分类与比较框架, 黑体字表示必须建模的元素

如上所述, 构成体系结构描述的三要素是:构件, 连接子和体系结构配置. 因此, 一个ADL 应该提供至少这三种元素的显式描述. 是否同时描述了这三种元素, 也可以

作为判断一个描述语言是否是一个体系结构描述语言的依据. 为了能够对体系结构的一些信息进行推理, 也要求ADL 能够对构成体系结构的构件的接口进行建模, 如果没有接口的描述, 体系结构描述就和线框图没有什么本质区别. 关于构件, 连接子, 配置的其它一些相关方面的描述, 如果有则更好, 但是如果没有提供, 也不表示这个语言不是ADL , 也即这些方面不是判断一个语言是否ADL 的关键标准. 以下分别就该分类框架中对三要素和工具支持方面的要求进行详细介绍, 最后我们给出使用该分类框架对ADL 进行分类和比较的结果.

对构件进行建模

在体系结构中, 构件是系统中的功能单元或数据存储单元. 构件可以小到一个函数, 大到整个系统. 一个构件即可以要求自己拥有独立的数据或运行空间, 也可以和其它构件共享. ADL 用来描述构件的特征如下:接口; 类型; 语义; 约束; 演化; 非功能属性. 下面分别做一些讨论.

接口. 构件的接口是构件和外界环境进行交互的交互点的集合, 指定了一个构件向外界提供的服务(消息, 操作和变量). 为了协助构件和包含该构件的体系结构进行推理, ADL 还应该提供描述构件需求的能力, 即该构件向外界提供功能的同时, 需要外界对它提供那些服务. 这样, 接口就区分成为两种, 一种是构件的对外接口, 一种是构件需求外界提供服务的接口. 简单地说, 接口定义了计算的合约和使用服务的约束.

类型. 构件类型是封装了可复用功能的抽象. 一个构件类型可以多次实例化, 在一个体系结构中多次使用或跨越不同的体系结构使用. 构件类型可以参数化, 使得其具有更强的可复用性. 因为构件类型刻画了其所有实例所共有的属性和特征, 因此可以协助体系结构的理解和分析.

语义. 构件的语义是指其行为的高层模型. 这样的模型可以用来进行分析, 加强体系结构约束和保证体系结构从一个抽象层次向另一个抽象层次映射时的一致性. 约束. 约束是指关于系统或系统的一部分的属性或断言, 对该属性或断言的违背将使得系统不可接受或至少降低了其满意度. 为了使得构件的使用达到预期的效果, 限制构件使用的范围以及建立构件内部成分之间依赖, 对构件的约束必须被指定. 演化. 作为体系建构的重要部分, 构件在进行着不断地演化. 构件的演化可以简单地认为是对构件某些特征, 如接口, 行为或实现, 的修改. ADL 可以通过采用子类型化或精化等手段来使得构件的演化以一种系统化的方式进行.

非功能属性. 一个构件的非功能属性(如安全, 性能, 易移植性等) 不能从其行为中直接导出. 这些属性的早期指定(在体系结构层次), 是使得运行时刻行为的模拟, 性能分析, 加强约束, 构件实现到处理器的映射以及协助项目管理所必须的. 对连接子进行建模

连接子是体系结构中对构件之间的交互和管理这些交互的规则进行建模的重要元素. 与构件不同, 连接子在实现系统中可能并没有实现体与之对应, 它们可能被实现为消息路由, 但是也可能仅仅是共享变量, 数据库表项, 缓冲, 对连接器的指定, 动态数据结构, 初始参数, 客户服务器协议, 内嵌在代码中的过程调用序列等等. 刻画连接子的特征有:接口; 类型; 语义; 约束; 演化; 非功能属性.

接口. 连接子的接口是连接子和与之连接的构件或其它连接子进行交互的交互点集合. 连接子本身不提供任何特定应用的计算, 它只是将与之连接的构件的功能导出给其它构件. 连接子的接口使得构件之间能够正确连接和交互, 从而, 对于体系结构配置的推理起到重要的辅助作用.

类型. 连接子类型是封装了构件通信, 协调和仲裁策略的抽象. 体系结构层次的交

互可能是很复杂的协议, 使得这些复杂的协议能够在体系结构中或跨体系结构复用, 需要ADL 提供将连接子描述为类型的能力. 这通常可以使用两种方式实现, 一是作为可扩展的类型系统, 按照交互协议来定义, 二是作为内嵌的枚举类型, 基于特殊的实现机制.

语义. 与构件的语义相类似, 连接子的语义是连接子行为的高层模型. 但是与构件也有区别. 构件的语义表达了特定应用的功能, 而连接子语义则承担了对(与计算无关的) 交互协议的规约. ADL 应该支持连接子语义的建模, 因为这样可以使得能够对构件的交互进行分析, 保证不同抽象层次的体系结构的精化的一致性, 还可以强化连接和通信的约束.

约束. 连接子约束保证了交互协议的使用达到了预期的目的, 建立了连接子内部的依赖关系, 并强化了使用界限. 一个即简单又能说明约束问题的例子是, 限制能够和一个连接子建立连接并通过该连接子进行交互的构件的数量. 要保证复杂的连接子约束(如最小吞吐量), 可能需要该连接子外部的信息, 如与该连接子连接的构件的动态语义的模型.

演化. 与构件的演化相类似, 连接的演化是指对连接子的特征, 如接口, 语义或约束的修改. 体系结构中构件的交互往往是使用的复杂并且会发生变化和扩展的协议, 而构件和配置也在不断的演化中. ADL 应该能够包容这些演化, 通过对已有连接子进行修改或精化, 修改或精化可以采用诸如增量信息过滤技术, 子类型化和精化等技术.

非功能属性. 连接子的非功能属性不能完全从它的语义规约中得到. 非功能属性是指连接子正确实现所必须满足的(额外) 需求. 对连接子的非功能属性进行建模, 可以在设计阶段对连接子的运行时刻行为做模拟, 对连接子进行分析, 加强约束, 以

及便于从产品化连接子(如消息总线) 的正确挑选.

对配置进行建模

体系结构配置, 或称拓扑结构, 是由描述系统结构的构件和连接子连接而成的图. 体系结构配置信息具有重要的意义, 它可以确定构件是否被正确地连接, 它们的接口是否匹配, 连接这些构件的连接子是否实现了正确的通信, 构件和连接子组合在一起的语义是否符合所希望的行为等. 和构件和连接子模型一起, 配置的描述使得可以对体系结构的并发和分布方面的性质进行评估, 如评估是否存在死锁, 性能, 可靠性, 安全性如何等等. 配置的描述也为分析一个体系结构是否符合设计理念(如构件的直接连接将降低体系结构的演化能力) 和是否满足体系结构风格约束(如构件之间的直接通信连接是被禁止的) 提供帮助.

体系结构配置的特征可以分为以下的三个类别:

配置描述的性质, 包括易理解性, 可组装性, 可精化和追踪性以及异构性. 被描述系统的性质, 包括异构性, 伸缩性, 演化性和动态性.

被描述系统的特性, 包括动态性, 约束和非功能属性.

上述的三个类别并不是正交的, 异构性和动态性出现在两个类别中. 异构性可能在配置描述中采用的多种形式化和在系统实现中采用的多种程序语言中表现出来. 可以预知的动态性是系统的一个属性, 这个属性指的是系统通过特殊的体系结构设计来包容这些(可预测) 的动态变化; 不可预知的动态性是系统的一个性质, 即系统面对动态变化所展现出的适应能力.

易理解性. 软件体系结构的一个重要角色就是作为项目中不同人员之间进行交流的媒介, 使得在一个高的抽象层次上的系统(或系统家族) 的理解更容易. 这样, 就要求ADL 必须以一种简单且易于理解的语法来对结构(或拓扑) 信息进行建模. 并且,

理想的情况是, 不需要对构件和连接子的模型规约进行仔细研究, 就可以比较清楚地理解体系结构的配置规约.

可组装性. 可组装性, 或称层次化组装, 是允许体系结构以不同的细节层次描述软件系统的机制. 如, 复杂的结构或行为可以显式地表示出来, 也可以将它们抽象为一个简单构件或连接子; 一个完整的体系结构可以成为另外一个更大的体系结构中某个构件的内部结构. 这种抽象机制应该作为ADL 建模能力的一部分.

可精化和追踪性. 除了为架构师提供丰富语义精致的设施来指定体系结构外, ADL 还必须提供能够让体系结构正确地精化为可运行系统, 并且能够在不同层次的体系结构精化之间保持追踪性的能力. 这正是ADL 能够出现并得以发展的一个重要原因:在非形式化的" 线框图" 和程序语言之间建立桥梁, 因为程序语言对于设计来说, 抽象层次太低了.

异构性. 体系结构的一个目标便于大型系统的开发, 更可取的是利用已有的不同粒度, 可能使用不同的形式语言定义, 使用不同的编程语言实现, 拥有不同的操作系统需求, 支持不同的通信协议的构件和连接子来设计. 这要求ADL 必须是开放的, 也就是说, ADL 应该提供一些设计和机制, 使得能够使用异构的构件和连接子来进行体系结构的规约和开发. 也就是要求ADL 支持异构的构件和连接子可以在一个体系结构中共同完成系统的设计.

伸缩性. 体系结构的目的就是能够为开发者提供用来解决系统的复杂性和大规模问题的. 从而, ADL 必须能够直接支持大型系统的规约和开发, 并且这样的系统有可能变得更大.

演化性. 一个新的软件系统不可能将所有不可预测的功能也包含进去, 而是采用某种演化方式. 一个体系结构的演化反映了一个软件系统家族的演化, 也使得这种演

化变成可能. 演化(即维护) 是软件开发最昂贵的活动, 因此系统演化性成为基于体系结构开发的关键方面. ADL 需要在构件和连接子的级别增强演化的支持, 允许构件和连接子的增量添加, 删除, 替换, 以及在配置中重新连接.

动态性. 演化多是指的" 离线" 对体系结构(以及目标系统) 的修改, 而动态性是指的在系统运行过程中对系统的体系结构进行修改并影响运行系统. 对动态性的支持对于那些关键系统, 如航空控制, 交换机等, 是非常重要的, 如果为了升级这些系统必须关闭这些系统才能进行, 那将造成极大的损失. 为了支持基于体系结构的运行时刻演化, ADL 需要提供特别的描述能力来对动态变化进行建模, 提供特别的技术能够在运行系统中实现这些变化.

约束. 体系结构级的约束描述了一个配置中的依赖关系. 这些约束是对单个构件和连接子的约束的补充. 很多体系结构级全局约束是直接从一些局部的约束导出的, 或者间接地依赖这些局部约束. 例如, 配置的约束可能通过组成这个配置的构件和连接子的交互约束来表达, 而这些约束又可能用它们的接口和协议来表达. 通过配置来表达的系统性能将以来每一个单独的体系结构元素. 体系结构级的安全也是它的组成部分安全的责任.

非功能属性. 某些非功能属性是系统级的, 而不是单个的构件或连接子的. 配置级非功能属性对于选择正确的构件和连接子, 执行分析, 强化约束, 映射体系结构构造元素到处理单元以及协助项目管理是必须的.

体系结构描述的工具支持

开发形式化语言作为体系结构描述背后的动机, 是因为形式化语言适合被软件工具用来进行推理和操纵. 尽管工具支持并不能算是体系结构描述语言的一部分, 但是体系结构描述语言的可用性与提供一个支持体系结构设计, 分析, 演化甚至可执

行系统的生成等等能力的工具是息息相关的. 体系结构描述语言工具支持的重要性已经被研究人员所重视. 当前体系结构描述语言所能提供的工具支持的功能大致可以分为如下几种:主动规约, 多视图, 分析, 精化, 实现生成和动态性.

主动规约. ADL 工具根据当前体系结构的状态缩小设计的可选择范围, 提供主动的规约支持. 这样的工具提供了设计指导, 极大地降低了体系结构设计人员的认知负荷. 这种支持可以是前摄式的, 建议一些活动的执行过程或禁止一些可能引起不希望出现的状态的设计选择; 也可以是反应式的, 当出现了不希望的状态时, 提醒设计人员. 这种支持可以是强制性的, 要求出现不希望的状态时, 设计人员必须马上处理, 否则将不能进行下去; 也可以是非强制性的, 设计人员可以在适当的时候进行处理.

多视图. 在设计体系结构时, 不同的人员(如架构师, 开发人员, 管理人员, 客户等) 可能要求体系结构的不同视图. 为客户提供一个简单的, 高抽象层次的" 线框图" 可能就使他们满意, 但是开发人员可能需要详细的(甚至形式化的) 构件和连接子规约, 而管理人员可以需要与系统开发过程相关的视图来更好地完成项目的管理. 为特定的人员提供特定的视图, 并且能够保证视图之间的一致性, 是ADL 工具需要关注的重要问题.

分析. 体系结构描述经常被用来对大型分布式并发系统进行建模. 对这些系统的一些属性, 在体系结构这样一个较高抽象层次上进行评估的能力, 可以大大地缩小错误所带来的开销. 并且体系结构描述是大粒度的抽象, 屏蔽了很多细节, 使得对体系结构级的分析比对代码级的分析容易. 从而, 体系结构分析成为ADL 工具开发者的一个主要关注点.

精化. 不少文献对支持体系结构的精化做了简要探讨, 认为在不同的体系结构细节

层次间的精化支持是非常重要的. 对体系结构描述的精化是一项复杂的任务, 其正确性和一致性不能完全地依靠形式化证明来保证, 足够的工具支持可以给设计人员在这方面增加一些自信.

实现生成. 任何软件设计和建模的努力其最终目标是产生一个可执行系统. 一个设计优美的体系结构模型如果不能够转换到运行系统, 就没有太大的价值. 通过手工的方式将体系结构转换到运行系统很导致很多一致性和追踪性方面的问题, 从而, ADL 工具能够提供代码生成的支持将是非常有意义的.

动态性. 前面已经讨论了在体系结构层次对动态变化进行建模的必要性. 但

是, ADL 只是具有对动态变化建模的能力是不够的, 不能保证这些变化能够以一种正确的方式被应用到运行系统中. 这要求提供工具的支持, 用来分析被修改的体系结构, 保证其中的一些重要特性, 将使用体系结构元素描述的变化映射到运行系统的模块上, 同时保证系统关键模块的不间断运行, 在修改过程中保持系统的状态, 并能够分析和测试正在运行的系统.

比较结果

根据该分类框架, 我们选取上述ADL (UniCon,Darwin,C2 SADL,Acme,xADL)进行比较.

从整体上看, 参与比较的所有ADL 都提供了对构件建模的全面支持, 所有的ADL 都将构件作为一阶实体, 区分构件类型和实例, 并且都对接口建模提供了支持. 但是, 这些ADL 都不支持演化和非功能属性.

在对连接子进行建模方面, 有Darwin 没有将连接子作为一阶实体来看待; 但是所有对连接子进行显式建模的ADL 都提供了对连接子接口的建模, 并区分连接子类型和实例.

在对配置进行建模方面, 尽管不同的体系结构描述语言中提供的构件和连接子的能力各不相同, 但是所有体系结构描述语言都能描述系统的拓扑结构; 至于演化性, 动态性等方面的支持, 不同语言的支持程度各有不同.

以上是对上述ADL 对构件建模和连接子建模的支持的简要比较, 详细的比较结果请参看表 - 2,表 - 3和表 - 4.

体系结构描述语言的构件建模能力比较

UniCon

Darwin

C2 SADL

ACME

xADL

特性

构件, 实现独立

构件, 实现独立

构件, 实现独立

构件, 实现独立

构件, 实现独立

接口

接口用player 进行建模

接口用service 进行建模(区分provided 和required)

接口区分provided 和required, 接口信息通过顶层port 和底层port 输出 用port 建模

接口用interface 进行建模

类型

预定义类型

可扩展类型系统, 支持参数化

可扩展的类型系统

可扩展的类型系统, 通过模板进行参数化

可扩展的类型系统, 可自定义类型

语义

属性列表中的事件踪迹

π演算

用一阶逻辑描述的构件不变量和前置, 后置操作

不支持, 不过能在属性列表中使用其它ADL 的语义模型

不变量和前置, 后置条件

约束

通过接口和语义进行约束; 属性; 对构件类型所能提供的player 进行限制 通过接口和语义进行约束

通过接口和语义进行约束; 风格不变量

仅通过接口进行约束

通过接口和语义进行约束

演化

各种子类型化

使用extends 对结构进行子类型化

支持产品线建模, 版本建模

非功能属性

用于可调度性分析的属性

通过属性列表进行定义, 但不对其进行操作

体系结构描述语言的连接子建模能力比较

UniCon

Darwin

C2 SADL

ACME

xADL

特性

支持显式的连接子

内嵌的绑定; 不对构件交互进行显式建模

支持显式的连接子

支持显式的连接子

支持显式的连接子

接口

用role 进行建模

无; 允许定义" 连接构件"

通过独立的port 与构件进行交互, 接口区分provided 和required 用role 进行建模

用interface 进行建模

类型

预定义连接子类型

基于协议的可扩展类型系统

基于协议的可扩展的类型系统; 使用模板实现参数化

可扩展的类型系统, 可自定义类型

语义

隐含在连接子类型中; 可以使用属性列表定义语义信息

通过消息过滤器支持部分语义

不支持, 但可以在属性列表中使用其它ADL 的语义模型

不变量和前置, 后置条件

约束

通过接口进行约束; 能够限制指定的role 所能连接的player 类型

通过语义进行约束; 风格不变量(每个port 只与一个链接相关)

通过接口和类型对实例进行约束

通过接口和语义进行约束

演化

上下文反射接口; 可演化的过滤机制

通过extends 对结构进行子类型化

支持产品线建模, 版本建模

非功能属性

用于可调度性分析的属性

通过属性列表进行定义, 但是不对其进行操作

体系结构描述语言对配置的建模能力的比较

UniCon

Darwin

C2 SADL

ACME

xADL

特性

使用显式的连接子来描述配置

内嵌的绑定

显式的体系结构拓扑结构

显式的attachment

使用显式的连接子来描述配置

易理解性

显式的文本和图形化规约; 配置描述可以是分布式的

许多连接子细节体现在内嵌的文本规约中; 提供了图形化符号

显式的精确的文本与图形化规约

显式的精确的文本规约

显式的精确的文本规约

组装性

通过复合构件和连接子实现组装

通过其语言中的复合构件实现组装

支持组装; 通过内部构件的体系结构加以支持

模版, 表示层以及表示层映射

通过复合构件和连接子实现组装

精化/易追踪性

支持系统生成; 对实现有所限制

对实现进行限制后能支持系统生成

表示层映射

支持系统生成; 有一定的工具支持

异构性

仅支持预定义的构件和连接子类型; 支持构件的包装

允许用多种语言对原子构件的语义进行建模; 支持C++开发

通过内部构件的体系结构加以支持; 支持Java,C++和Ada 的开发

开放的属性列表; 需要显式的ADL 之间的映射

支持不同语言的实现体; 实现与规约分离

易伸缩性

受益于显式的配置和可变数目的连接子角色

受制于内嵌的配置

得益于显式的配置和可变的连接子端口; 用于自身工具集的构建

得益于显式的配置; 但受制于固定的角色数量

得益于显式的配置; 使用schema 从而具有schema 的可扩展性

演化性

对体系结构的局部描述提供了部分支持; 受益于显式的配置

不支持体系结构的局部描述; 受制于内嵌的配置

支持体系结构的局部描述; 受益于显式的的配置; 构件间的相互依赖最小化; 异构的连接子

受益于显式的配置; 一阶的家族概念

受益于显式的配置; 支持产品线和版本概念

动态性

有限的动态性; 支持构件的运行时复制和带条件判断的配置

不可预期的动态性; 支持元素的插入, 删除与重新连接

使用variant 支持一定的动态能力

约束

连接子只能和role 相连

Provided 服务只能与required 服务相连

确定的风格不变量

Port 只能与role 相连

构件的interface 只能与连接子的interface 相连

非功能属性

通过属性列表进行定义, 但是不对其进行操作

参考文献

Medvidovic N. and Taylor R., "A Classification and Comparison

Framework for Software Architecture Description Languages", IEEE Transactions on Software Engineering, Vol.26, No.1, 2000

Allen R. and Garlan D., "A formal Basis for Architectural Connection",

ACM Transactions on Software Engineering and Methodology, July, 1997. Luckham D. and Vera J., "An Event-Based Architecture Definition Language", IEEE Transactions on Software Engineering, Sept., 1995.

Shaw M., Deline R., Klein D.V., Ross T.L., Young D.M. and Zelesnik G., "Abstractions for Software Architecture and Tools to Support Them", IEEE Transactions on Software Engineering, April 1995

Garlan D., Monroe R. and Wile D., "Acme: An Architecture Description Interchange Language", In Proceedings of CASCON'97, Nov 1997. Dashofy E., Hoek A., and Taylor R., "A Highly-Extensible, XML-Based Architecture Description Language", In Proceedings of the Working IEEE/IFIP Conference on Software Architectures, 2001.

C. Ghezzi, M. Jazayeri, and D. Mandrioli, Fundamentals of Software Engineering. Prentice Hall, 1991.

M. Shaw and D. Garlan, Formulations and Formalisms in Software Architecture, Computer Science Today: Recent Trends and

Developments. J. van Leeuwen, ed. Springer-Verlag, 1995.

M. Moriconi, X. Qian, and R.A. Riemenschneider, Correct Architecture Refinement, IEEE Trans. Software Eng., vol. 21, no. 4, pp. 356-372, Apr. 1995.

P. Oreizy, N. Medvidovic, and R.N. Taylor, Architecture-Based Runtime Software Evolution, Proc. 20th Int'l Conf. Software Eng. (ICSE '98), pp. 177-186, Apr. 1998.

D. Garlan, J. Ockerbloom, and D. Wile, Towards an ADL Toolkit, EDCS Architecture and Generation Cluster, Dec. 1998.

http://www.cs.cmu.edu/~spok/adl /index.html.

D. Garlan, Style-Based Refinement for Software Architecture, Proc.

Second Int'l Software Architecture Workshop (ISAW-2), A.L. Wolf, ed., pp. 72-75, Oct. 1996.

architecture StackVisualizationArchitecture is

components

top_most StackADT;

internal StackVisualization1; StackVisualization2;

bottom_most GraphicsServer;

connectors

connector TopConnector is

message_filter no_filtering

end TopConnector;

connector BottomConnector is

message_filter no_filtering

end BottomConnector;

architectural_topology

connector TopConnector connections

top_ports StackADT;

bottom_ports StackVisualization1; StackVisualization2;

connector BottomConnector connections

top_ports StackVisualization1; StackVisualization2;

bottom_ports GraphicsServer;

end StackVisualizationArchitecture;

archInstance{

componentInstance{

(attr) id = "client1"

description = "Client"

interfaceInstance{ (attr) id = "client1.IFACE_TOP" …… }

interfaceInstance{ (attr) id = "client1.IFACE_BOTTOM" …… } }

connectorInstance{

(attr) id = "conn1"

description = "Connector"

interfaceInstan ce{ (attr) id = "conn1.IFACE_TOP" …… }

interfaceInstance{ (attr) id = "conn1.IFACE_BOTTOM" …… } }

componentInstance{

(attr) id = "server1"

description = "Server"

interfaceInstance{ (attr) id = "server1.IFACE_TOP" …… }

interfaceInstance{ (attr) id = "server1.IFACE_BOTTOM" …… } }

linkInstance{

(attr) id = "link1"

description = "Comp1 to Conn1 Link"

point{ (link) anchorOnInterface = "#client1.IFACE_BOTTOM" } point{ (link) anchorOnInterface = "#conn1.IFACE_TOP" } }

linkInstance{

(attr) id = "link2"

description = "Conn1 to Comp2 Link"

point{ (link) anchorOnInterface = "#conn1.IFACE_BOTTOM" } point{ (link) anchorOnInterface = "#server1.IFACE_TOP" } }

}

component Server{

provide p;

}

component Client{

require r;

}

component System{

inst

A: Client; B: Server;

bind

A.r – B.p ;

}

component pipeline (int n) {

provide input;

require output;

array F[nl:filter;

forall k:0..n-i {

inst Flk];

bind F[kl.output -- output:

when k

F[k].next -- F[k+ 1].prev;

}

bind

input -- F[O].prev;

F[n-1].next-- output;

}

System simple_cs =

{

Component client = { Port send-request; };

Component server = { Port receive-request; };

Connector rpc = { Roles { caller, callee}};

Attachments {

client.send-request to rpc.caller;

server.receive-request to rpc.callee;

}

StackVisualizationArchitecture.remove(StackVisualization1); StackVisualizationArchitecture.unweld(TopConnector, StackVisualization1);

StackVisualizationArchitecture.unweld(StackVisualization1, BottomConnector);

:==

|

:==

IMPLEMENTATION IS

END IMPLEMENTATION

:== VARIANT IN ""

END

:==

IMPLEMENTATION IS

END IMPLEMENTATION

:==

|

|

|

:==

COMPONENT

END

:==

INTERFACE IS

TYPE

END INTERFACE

:==

Module | Computation | SharedData | SeqFile | Filter | Process

| SchedProcess | General

:==

CONNECTOR

END

:==

PROTOCOL IS

TYPE

END PROTOCOL

:==

DataAccess | FileIO | Pipe | PLBundler

| ProcedureCall | RemoteProcCall | RTScheduler :==

IMPLEMENTATION IS

BUILTIN

END IMPLEMENTATION


    相关文章

    基于Z-ADL语言的动态体系结构描述语言

    软 件 体 系 结 构 课 程 论 文 --动态体系结构描述语言Z-ADL 动态体系结构描述语言Z-ADL 摘 要: 软件动态演化已成为软件发展的新动力,为便于软件体系结构的形式化描述,对现有的一些ADL 扩展以支持体系结构的动态性.本文简 ...

    软件设计与体系结构

    1. 2. 3. 4. 5. 面向对象编程中是如何体现封装性的? 面向对象编程的重载和重写的含义是什么? 什么是接口回调?其过程细节是怎样的? 是举例说明什么是组合关系和依赖关系? 距离说明什么是抽象类和接口,有什么区别,如何应用它 们? ...

    软件体系结构

    软件体系结构试题 一 .选择题 1.设计模式一般用来解决什么样的问题( a) A.同一问题的不同表相 B不同问题的同一表相 C.不同问题的不同表相 D.以上都不是 2.下列属于面向对象基本原则的是( c ) A.继承 B.封装 C.里氏代换 ...

    浅谈软件体系结构评估技术

    浅谈软件体系结构评估技术 摘要: 作为在软件生命周期早期保障软件质量的重要手段之一,软件体系结构评估技术是软件体系结构研究中的一个重要组成部分.现有的软件体系结构评估方法可以划分为3类:基于场景的评估方法.基于度量和预测的评估方法以及特定软 ...

    005 道路交通事故致轻度精神伤残者功能障碍评定

    法医学杂志2014年2月 第30卷第1期・23・ 道路交通事故致轻度精神伤残者功能障碍评定 张钦廷1-一.周晓蓉1.高 东1,汤 涛1,樊慧雨1 (1.司法部司法鉴定科学技术研究所上海市法医学重点实验室,上海200063:2.上海交通大学医 ...

    6-不同养老方式下老年人日常生活能力的比较研究

    988 中国康复理论与实践2009年10月第15卷第10期Chin J Rehabil Th eory Pract, Oct. 2009, Vol. 15, No. 10 社区康复 不同养老方式下老年人日常生活能力的比较研究 张保利, 兰志 ...

    一种状态事件故障树的定量分析方法

    第8期2013年8月 电 子 学 报Vol.41 No.8 一种状态事件故障树的定量分析方法 23 徐丙凤1,黄志球1,胡 军1,,魏 欧1,肖芳雄1,(1.南京航空航天大学计算机科学与技术学院,江苏南京210016:2.南京大学计算机软件 ...

    嵌入式开发工具发展趋势

    嵌入式开发工具发展趋势 时间:2009-01-15 13:58:53 来源:单片机与嵌入式系统 作者:李宁 宋薇 周薇 引 言 近年来嵌入式领域得到了迅猛发展,嵌入式系统已经无处不在,嵌入式系统的开发也变得越来越复杂,软硬件的复杂度都大幅度 ...

    2014年医师定期考核试题及答案(康复试题)

    2014年北京市医师定期考核业务水平测评 (康复专业试卷) 单位:__________________________________________ 姓名:________________ 性别:_________ 身份证号:______ ...