`
modabobo
  • 浏览: 510079 次
文章分类
社区版块
存档分类
最新评论

OSGi规范中文版(第5版 core R5.0.0)-第3章模块层(Module Layer)2

 
阅读更多

3.3 依赖

OSGi依赖处理基于非常普通的模型来描述依赖关系,这个模型有一些小的原始概念:

  • 运行环境-framework安装资源的容器
  • Resource-抽象的artifact需要以某种方式安装后,来提供预期的功能。Bundle是一个资源模型,例如显示器或者USB密钥都是resource。
  • Namespace –定义运行环境在给定的命名空间中匹配requirement和capability
  • Capability –描述在运行环境中install的resource特性和功能,capability包含属性和指令。
  • Requirement –声明capability在运行环境中的可用性。Requirement包含属性和指令。filter指令包含在 同一个namespace中进行过滤的属性断言。 在图3.2种描述了这几个实体之间的关系:1图 3.2 Core Requirement/Capability模型 通常一个Resource会依赖其他Resource或者被其他Resource依赖。

Dependency类型变化很大,如一个Bundle能够从别的Bundle(Import-Package)中要求package,或者一个Fragment需要主Bundle(Fragment-Host),或者Bundle要求接入高分辨率显示器。OSGi Core规范用专用的header描述不同类型的可能依赖,以及每一种情况下的优化,然而,这个模型要求依赖的各种类型通过一个规范的过程处理,并且有效的限制各方不参与这个过程。因此,规范中提供了一个基于namespace的通用依赖模型,namespace是dependency的一个类型。例如,osgi.wiring.package Namespace通过指定数量的属性和指令定义了Import-Package和Export-Package语义。另外为匹配和指令使用属性提供了关于Namespace的语义信息,例如在osgi.wiring.host Namespace (Fragments)下,对应capability属性有:

  • osgi.wiring.host – (String) host name.
  • bundle-version – (Version) host version.
  • * –允许其他任意属性 OSGi Framework Namespace定义的类,具体可参考第8章Framework Namespace规范

Namespace的目的是创建一组属性/指令基础语言,这个基础语言描述了通用的dependency与具体dependency类型无关性,另外Namespace的数量在OSGi联盟和其他规范中也有所定义,并且OSGi namespace开头保留osgi.前缀,例如,osgi.ee这个namespace定义了指定可执行环境下的capability。Namespace也能被其他组织和个人定义,故为了减少命名空间冲突,使用package和bundle symbolic name时建议使用反向域名规则。OSGi组织推荐注册的Namespace,可参考[16] OSGi Header Namespace Registry to prevent clashes。

指定一个Namespace,可以声明为Namespace的capability。Capability也提供了定义在namespace下的属性和指令。例如,在osgi.wiring 包Namespace中可以转化Export-Package头信息到capability。

指定一个capability,可以声明为requirement。如果requirement是需要满足的一些条件的话,Requirement则使用filter来作为匹配capability的属性,Requirement通常关联Namespace。Requirement使用的filter条件指令匹配capability,filter语法标准参考3.2.7 Filter语法。Requirement有2种属性(mandatory或optional)来描述指令集使用。Requirement可以有一个或者多个基数,表明它至少需要一个或者更多的Capability。

当Resource强制要求由一个或者多个Capability满足时,Resource则声明requirement来提供其预期的功能,Capability通常由其他Resource提供。Resource认为所有的mandatory requirement都是要解决的,而且必须是通过Resource的Capability所提供的功能描述来满足requirement。Capability只有在Resource被resolve时才需要满足requirement要求。

匹配requirement capability的处理过程被称为resolving。在这个处理过程中,resolver必须创建wire(wire是指和requirement/Capability的一种连接关系)。Wire和requirement/Capability存在引用关联Resource。在某些情况下,requirement/ capability可以在一个Resource中声明,但是会有来自其他Resource的wire。然而,当一个Resource有wire,那么wire具有相应provider或者requirer声明的不同Resource。声明Resource用于不同的provider或者requirer的过程称为hosting。这种分割形成Fragment,Fragment包含一些主要的requirement/Capability以及关联Fragment的其他部分。

只有有效的requirement必须被wire,而且每个requirement的目的是为了保持一定的系统状态。例如,OSGi Framework只根据requirement的有效指令设置去resolve。

一旦一组Resource在运行环境中被resolve了,那么OSGi Framework会给Bundle的每个Resource创建Wiring来保持resolve状态,这个状态无论如何都会包含wire信息。

Wire在requirement和capability之间必须根据他们之间的Namespace语义创建。Wire在resolve操作中产生,并运行在指定的Namespace中使用。例如,osgi.wiring.*这个Namespace将控制class加载(具体参考第7章Bundle Wiring API 标准)。而且也能通过Namespace描述其他服务,例如,wire能指定Dependency注入的source和target。

通常模型的接口定义在org.osgi.resource。在Bundle Wiring API规范中描述了wiring API基于这个普通的package,一般API会兼容其他规范(OSGi Core framework’s Capability /Requirement模型)。

3.3.1 Bundle

所有的Bundle依赖一个或者多个外部实体,这种关系通过requirement和Capability表达。
当Bundle第一次被resolve时,会假设所有的依赖关系是可满足的。Manifest的Require-Capability和Provide-Capability头信息将requirement和Capability都声明在Namespace中。于是,一些在OSGi规范中的manifest头在Capability中指定了其他OSGi manifest头的真实requirement。例如,一条Import-Package clause在capability中指明一条require Export-Package clause。Import-Package clause的属性与Export-Package clause属性相对应。故规范中也为OSGi manifest header预留了一些Namespace:osgi.wiring.bundle, osgi.wiring.package, osgi.wiring.host。这些Namespace会影响resolver和定义类加载处理过程,例如,Require-Bundle clause是一个requirement时,将会确保依赖Bundle export过的package在对应依赖的类加载中是有效的。
OSGi resolve过程在3.8解析过程中描述。图3.3描述了Requirement/Capability模型。
3_3
图3.3

3.3.2 使用示例

Bundle在window中指定java规范版本以及require一个显示器像素为1000x1000,并且依赖于IP-number-to-location table。
这些依赖关系在运行环境中使用如下的规则描述(其他Bundle也可以这样使用):
Require-Capability:
com.microsoft; filter:="(&(api=win32)(version=7))",
com.acme.display; filter:="(&(width>=1000)(height>=1000))",
com.acme.ip2loc
每一条clause存在namespace,例如com.microsoft。namespace定义了语义属性以及可选的规则。
环境部署时设置启动属性来启动framework:
org.osgi.framework.system.capabilities.extra = «
com.acme.display; width:Long=1920; height:Long=1080; interlace=p, «
com.microsoft; edition=home; version:Version=7; api=win32
com.acme.ip2loc

Framework已经有需要的display requirement,但是ip2loc table requirement还没有的时候,部署环境将会install ip2loc table Bundle,这个Bundle的header如下:
Provide-Capability: com.acme.ip2loc; version:Version=1.2
在install和resolve这个Bundle之后,framework就能将最初的Bundle resolve了。

3.3.3 Bundle Capability

Bundle的capability定义在Provide-Capability头中。这个头的语法如下:
Provide-Capability ::= capability ( ',' capability )*
capability ::= name-space
( ’;’ directive | typed-attr )*
name-space ::= symbolic-name
typed-attr ::= extended ( ’:’ type ) ’=’ argument
type ::= scalar | list
scalar ::= ’String’ | ’Version’ | ’Long’
| ’Double’
list ::= ’List<’ scalar ’>’

Header具有以下指令架构:

  • effective – (resolve)指定时间内capability是有效的,而且可以resolve(default)或者其他名字。OSGi framework resolver只考虑没有effective的指令或者effective:=resolve。Capabilty可以通过一个外部代理为effective指令使用其他值。
  • uses –uses指令列出需要使用的package名称。此信息用于uses约束。具体参考3.7.5Package约束。 而且Namespace能定义额外的指令和属性。

3.3.4 Bundle Capability属性

属性是可以定义类型的,类型的内容也非常重要,因为这定义了如何比较属性。在不提供比较语义版本的时候通过字符串比较版本,同样字典序的数值排序也是不同的。
类型描述在属性名和等号(’=’ \u003D)之间,用冒号(’:’ \u003A)分割;例如Long类型:
attr:Long=24
如果没有指定类型,那么会认为是String类型。

解析规则通过对应的String类型构造函数创建一个实例,并且放在capability的map中。数值类型必须去除value前后的空白符号,类型周围的其他空白符号也会被忽略,允许跳过manifest的空白符号规则检测的示例如下:
attr:Long= 23 , // ok
attr:Version=" 23 ", // error
attr:Long=" 23 ", // ok, because numeric

多个属性值可以通过List<>描述,List<>操作定义了一个泛型来重复参数值,参数值之间用逗号(’,’\u002C)分隔,相应的参数列表解析必须遵守以下规则:

  • 逗号附近的空白符号必须被去除
  • 逗号或者斜杠(’\’\u005C)是值的一部分,需要对他们使用斜杠进行转义。
  • 整个参数必须用双引号包含起来,因为逗号在manifest语法中是一个重要标志 version属性require Version类型的比较示例: version:Version=1.23 例如, Provide-Capability: « com.acme.dictionary; from:String=nl; to=de; version:Version=3.4, « com.acme.dictionary; from:String=de; to=nl; version:Version=4.1, « com.acme.ip2location;country:List="nl,be,fr,uk";version:Version=1.3,« com.acme.seps; tokens:List="\,,;,\\""

3.3.5 System Bundle Capability

Capability通过下面的运行属性提供system Bundle:
org.osgi.framework.system.capabilities
org.osgi.framework.system.capabilities.extra
这些系统属性的格式和Provide-Capability一样,framework必须解析这些属性,如果属性是system Bundle提供的,framework还需要在resolve过程中使用。
这2个属性以便framework通过org.osgi.framework.system.capabilities
属性指定framework默认的Capability,而通过org.osgi.framework.system.capabilities.extra system属性来具体部署Capability。Framework经常从他们的环境中演绎出许多Capability。
下面是system Bundle定义的capability header:
map.put("org.osgi.framework.system.capabilities.extra",
"com.acme.screen; width:Long=640; height:Long=480; card=GeForce");

3.3.6 Bundle Requirements

Bundle的Require-Capability header语法如下:
Require-Capability ::= requirement ( ',' requirement )*
requirement ::= name-space ( ';' parameter )*
Requirement的属性在Require-Capability中设置,提供这个属性的目的为requirement提供更详细的信息。
Import-Package, Require-Bundle, Fragment-Host这些头的属性映射在其对应的命名空间中的过滤指令里。
Require-Capability的指令架构如下:

  • effective – (resolve) 指定时间内capability是有效的,而且可以resolve(default)或者其他名字。OSGi framework resolver只考虑没有effective的指令或者effective:=resolve。Capabilty可以通过一个外部代理为effective指令使用其他值。
  • resolution – (mandatory|optional) mandatory表示requirement不满足时,是否还强制Bundle resolve;option表示如果requirement不满足时,是否还允许bundle resolve。当requirement都不能被resolve时则没有wiring,而且bundle尝试使用的package不能resolve时将会抛出ClassNotFoundException,如果设置了optional则可以不resolve。默认值是mandatory。
  • filter – (Filter) filter表达式指过滤出属于指定namespace的Capability。对capability的filter匹配是一次只匹配一个capability。假设filter= (&(a=1)(b=2)),那么正确需要匹配2个capability,这时候如果filter是optional的,那么filter指令也会竟然去匹配。
  • cardinality – (single|multiple)表示requirement可以被wire(指定引用集)一次或者多次,默认是single。 Additional directives are ignored during resolving. Attributes on the requirement clause are also ignored. 在resolve过程中额外的指令会被忽略,requirement clause属性也会被忽略。

3.4 运行环境

Java环境提供的所有package在java.这个namespace中,这个namespace没有很好的定义不同运行环境,例如,Java SE 5不同于Java SE 7,Android环境与Java SE环境有非常大的差异,然而,Java SE 6向后兼容Java SE 5, Java SE 1.4, Java SE 1.3 and Java SE 1.2,也就是说Java SE 1.3环境下的程序也能够运行在Java SE 5环境。
由于这些差异和向后兼容不能在运行时获取版本,例如,[21] Google Android是Java SE 5环境的变化,以及[22] Google App Engine and [23] Google Web Toolkit.在java.
namespace中有不同的package、type和method。
Bundle不能import java.的package,因此环境中不能在Import-Package头中指定这些的依赖。OSGi运行环境定义了framework如何在变化的执行环境中通知Bundle,运行环境的主要定义在java.namespace中,运行环境也包含其他package的namespace。
运行环境需要一些合适的名字识别变化:

  • Bundle resolve之前需要知道Framework提供的运行环境
  • 提供Framework的运行环境信息

3.4.1 Bundle-RequiredExecutionEnvironment

Bundle-RequiredExecutionEnvironment manifest header提供了osgi.ee capability功能,而且在多个运行环境下执行的Bundle必须约束在manifest文件,而且多个运行环境用多个逗号分隔表示:
20140417200055
例如:
Bundle-RequiredExecutionEnvironment: CDC-1.0/Foundation-1.0, «
OSGi/Minimum-1.1
如果Bundle包含这个header,那么Bundle只能使用在运行环境中签名过的方法。必须列出所有(已知)的运行环境支持Bundle运行。
如果framework运行在vm上,vm需要实现一种执行环境,而且Bundle只能resolve。Framework需要能够识别当前VM实现了多个运行环境,例如,Java 6向后兼容Java 5,但是Bundle需要在Java 6运行环境上那就必须在Java 6 VM上resolve。
Bundle-RequiredExecutionEnvironment头不能阻止Bundle的安装。org.osgi.framework.executionenvironment运行属性定义了当前运行环境名称(多个环境名称用逗号分隔)。如果没有设置,framework必须提供一个适当的值。这个属性不赞成使用,这个属性功能代替了org.osgi.framework.system.capabilities[.extra]。
例如:
org.osgi.framework.executionenvironment =JavaSE-1.5, J2SE-1.4, JavaSE-1.4, JavaSE-1.3, OSGi/Minimum-1.1

Framework必须使用Wiring API转换Bundle-RequiredExecutionEnvironment头到osgi.ee namespace中,具体可参考第7章Bundle Wiring API 规范。
由于header在运行环境中可以使用不透明的名字,而且在运行环境中没有保证的算法映射ee-name到Require-Capability头中,于是,建议名字使用目前流行的运行环境命名,这样也可以用来创建的一个header结构,ee-name里的bree语法结构如下:
bree’ ::= n1 ( ’-’ v )? ( ’/’ n2 ( ’-’ v )? )?
示例:
CDC-1.0/Foundation-1.0
OSGi/Minimum-1.2
J2SE-1.4
JavaSE-1.4

每一个Btree元素的匹配模式可以被转换为osgi.ee Require-Capability filter。第一个变量n1必须被替换成JaveSE(Require-Capability需要Java Standard Edition名称时),filter指令由n1,v,n2构成,如果n2或者v未定义,那么扩展的指令也是未定义的:
bree-filter ::= '(&(osgi.ee=' n1 ('/' n2 )? ') ( '(version=' v ')' )? ')'

如果bree指定部分不能被解析,那么必须如下样子:
filter ::= '(osgi.ee=' ')'
一些例子:
20140417200342

Bundle-RequiredExecutionEnvironment例子:
Bundle-RequiredExecutionEnvironment:
CDC-1.0/Foundation-1.0,
OSGi/Minimum-1.2,
J2SE-1.4,
JavaSE-1.6,
AA/BB-1.7,
V1-1.5/V2-1.6,
MyEE-badVersion
上述的Bundle-RequiredExecutionEnvironment例子必须转为如下的Require-Capability:
Require-Capability:osgi.ee; filter:="(|
(&(osgi.ee=CDC/Foundation)(version=1.0))
(&(osgi.ee=OSGi/Minimum)(version=1.2))
(&(osgi.ee=JavaSE)(version=1.4))
(&(osgi.ee=JavaSE)(version=1.6))
(&(osgi.ee=AA/BB)(version=1.7))
(osgi.ee=V1-1.5/V2-1.6)
(osgi.ee=MyEE-badVersion)
)"

每一个org.osgi.resource.Resource代表Bundle-RequiredExecutionEnvironment的Bundle,转换后的osgi.ee requirement可以通过getRequirements(String)获得。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics