3.11 本地化
在bundle中包含了大量可读性很强的信息。但是有些信息需要依据用户的语言、国籍以及其他指定的参数,或者由本地化(locale)的一些参数来转换。在本节描述了bundle中为manifest和其他依赖于本地化资源配置所提供的一种通用变换方法。
bundle本地化条目有一个通用的名称。为了找到潜在的本地化条目,约定下划线加上一个编号作为后缀,用下划线分开,最后加上一个.properties的后缀。在java.util.Locale中定义了这样的后缀规格。后缀的排序必须是:
- 语言(language)
- 国籍(country)
- 变量(variant)
例如,下面的示例表示用英语,德语和瑞典语描述的manifest:
OSGI-INF/l10n/bundle_en.properties
OSGI-INF/l10n/bundle_nl_BE.properties
OSGI-INF/l10n/bundle_nl_NL.properties
OSGI-INF/l10n/bundle_sv.properties
Framework通过在基本名称后面添加后缀的方式来查找本地化条目,即添加指定的本地化参数后加上.properties后缀。如果没有找到对应的转换文件,那么就逐步的减少参数,首先去掉变量信息,然后去掉国籍信息,最后是语言信息,直到找到了一个匹配的转换文件为止。例如,查找本地化的信息en_GB_welsh的查找过程如下:
OSGI-INF/l10n/bundle_en_GB_welsh.properties
OSGI-INF/l10n/bundle_en_GB.properties
OSGI-INF/l10n/bundle_en.properties
OSGI-INF/l10n/bundle.properties
这样允许本地化文件通过指定更详细的信息来覆盖没有指定详细信息的本地化文件。
3.11.1 查找本地化条目
本地化条目可以在bundle中,也可以在fragment中。Framework必须首先查找bundle,然后再查找fragment。而fragment必须将查找委托给具有最小bundle ID的附主bundle。
bundle的类加载器不能进行本地化条目的搜索。只对bundle的目录和附加的fragment进行搜索。而即使在bundle的类路径中没有逗号,也会对bundle搜索本地化条目。
3.11.2 本地化Manifest
本地化的值存储在Bundle的属性资源内。Bundle的本地化属性名字默认是OSGI-INF/l10n/bundle,Manifest头文件中的Bundle-Localization定义了默认本地化属性名字,本地化依赖于启动Bundle和bundle fragment。
localization entry包含了key-value结构的本地化键值对信息,而且bundle manifest中的所有header信息都可以本地化。但是,Framework必须使用一个与本地化无关包含有框架语义的版本信息。
header-value ::= ’%’text
text ::= < any value which is both a valid manifest header value and a valid property key name >
Bundle entry示例:
Bundle-Name: %acme bundle
Bundle-Vendor: %acme corporation
Bundle-Description: %acme description
Bundle-Activator: com.acme.bundle.Activator
Acme-Defined-Header: %acme special header
用户定义的header也可以本地化,在本地化的key中可以使用空格。
上面示例中的entry可以通过OSGI-INF/l10n/bundle.properties进行本地化。
# bundle.properties
acme\ bundle=The ACME Bundle
acme\ corporation=The ACME Corporation
acme\ description=The ACME Bundle provides all of the ACME \ services
acme\ special\ header=user-defined Acme Data
也可以将上面的manifest本地化entry为法国的OSGI-INF/l10n/bundle_fr_FR.properties文件。
3.12 Bundle的有效性
如果Manifest中没有指定Bundle-ManifestVersion的值,那么默认属性值是1。而且特定的R4语法中,一些新的manifest header将被忽略而不被认为是错误信息,R3标准的Bundle必须根据R3规范处理。
下面列出了导致Bundle安装失败的错误情况(不局限于以下情况):
- 缺失Bundle-SymbolicName
- 重复属性或者重复指令(除Bundle-Native code clause)
- Package的重复导入
- Export或者Import了java.*的package
- Export-Package, Bundle-SymbolicName,或者Fragment-Host中没有定义强制属性
- 安装或者更新Bundle时,已存在安装过同样symbolic-name和version的Bundle(具体参考4.4.1 Bundle标示符)
- 任何错误语法(例如,不合法的version格式或者是symbolic-name,不能识别的指令等)
-
Specification-version和version值指定不一样,例如:
Import-Package p;specification-version=1;version=2
将导致install失败, 但是:Import-Package p;specification-version=1, q;version=2
这种写法没有错误. -
Manifest中列举了OSGI-INF/permission.perm文件,但是却不存在这个文件
-
Bundle-ManifestVersion的值不等于2,除非以后的版本中有说明
-
2次以上Require相同symbolic-name的Bundle
3.13 Requiring Bundle
Framework支持Bundle之间的直接连接机制,而且不会去识别package中指定的信息。这一节中定义了一些相关的header,讨论Require-Bundle可能出现的情况(有时候无法预见的情况)。
3.13.1 Require-Bundle
在Manifest中的Require- Bundle头中定义了一个bundle symbolic-name的列表,它们会在import之后,在bundle的类路径搜索之前进行搜索。但是,对于提出require的bundle,只能在被require的bundle中,并且被require的bundle中为exported的包中可见。
Manifest中的Require-Bundle描述必须遵循以下语法:
Require-Bundle ::= bundle-description
( ',' bundle-description )*
bundle-description ::= symbolic-name // See 1.3.2
(';' parameter )*
在Require-Bundle中可以使用以下指令:
-
visibility – 如果值为private(Default),那么所有来自required bundle的可见package均不会被导出。如果值为reexport,那么所有的这些package会被提出require的Bundle导出,就好像这些package是在提出require的bundle中一样。例如,如果Bundle A require Bundle B,而且Bundle B require Bundle C(Bundle C有visibility:=reexport),那么Bundle A会获得Bundle C export出的package。
-
resolution – 如果值为mandatory (default),那么在解析提出Require的Bundle前,被Requrie的Bundle必须提前存在;如果这个值为optional,那么被Require的Bundle即使不存在,也不会影响提出Require Bundle的解析。
在Framework中还使用了以下属性:
- bundle-version – 这个属性是一个版本范围,描述Require Bundle的版本范围,参考3.2.6版本范围一节,默认值[0.0.0,∞)。 Bundle-SymbolicName头可以在Bundle被匹配前指定一个合适的值。
指定的symbolic-name只能被require一次,如果安装时require多次相同的symbolic-name会导致install失败。
对于Require bundle必须获取所有被require的bundle的export package。这意味着任何强制属性的export都会被忽略,如果被require bundle的export package取代import package,那么require bundle必须关联被requrie bundle的export package以确保类空间的一致性。
例如,Bundle A export package p以及Bundle B require Bundle A:
Bundle A
Export-Package: p;x=1;mandatory:=x
Import-Package: p
Bundle B
Require-Bundle: A
在这个示例中,Bundle B将会获得与Bundle A同样源码的package p,Bundle A能够优先选择自己Bundle中的export类,当然还能从别的Bundle中import,在所有情景中,Bundle B必须使用与Bundle A完全一样的package p。
某个给定的package可能同时在一个或者多个被require的bundle中提供,这样的情况是明确允许的,这种package称为拆分包(split packages)。拆分包没有在惟一的提供者中一次性提供,它的内容可以来自于不同的bundle。如下例:
A: Require-Bundle: B
Export-Package: p
B: Export-Package: p;partial=true;mandatory:=partial
如果Bundle C import package p,那么C将关联到package A.p,但是,实际的内容来自于B.p > A.p。B导出定义中的mandatory属性确保了B并不是作为p的随机提供者。拆分包也有一些缺陷,在(3.13.3 require bundle 的一些问题中)进行了讨论。
来自拆分包的类和资源是必须按照Require- Bundle中的顺序进行搜索。
例如,假设一个bundle由一系列的bundle和可选的语言资源(也可以是bundle)组成:
Require-Bundle: com.acme.facade;visibility:=reexport, «
com.acme.bar.one;visibility:=reexport, «
com.acme.bar.two;visibility:=reexport, «
com.acme.bar._nl;visibility:=reexport;resolution:=optional, «
com.acme.bar._en;visibility:=reexport;resolution:=optional
Bundle可以同时import package和require Bundle(一个或多个),如果通过Import- Package导入package,那么对于Require- Bundle而言是不可见的,这是因为Import- Package比Require- Bundle具有更高的优先级别(另外由require bundle导出和通过Import- Package导入的package不能被看作是拆分包)。
如果要require 一个具有名字的bundle,提出require的bundle必须有bundle权限(BundlePermission [, REQUIRE]),而且bundle的symbolic name其实是被require的bundle名称。同时被require的bundle必须提供这样的权限:BundlePermission[, PROVIDE]
3.13.2 split package兼容性
Package如果是split package,那么这个package有多个来源;而且只有Require-Bundle头描述中才能有split package。
来源可以是Bundle提供的package,required bundle以及require bundle都可以作为来源,但是required bundle和require bundle都只能贡献自己的export package。
如果package来源是其中一个bundle的子集,那么从2个Bundle中Export的split package是兼容的。
3.13.3 Requiring Bundle的一些问题
连接到bundle的方法建议通过Import- Package和Export- Package来进行,通过这个途径,importer和exporter之间耦合度会更小。可以将Bundle进行重构成具有不同的package结构,并且不会导致其他Bundle的安装失败。
Require- Bundle提供了一种忽略export内容、并能将某个bundle的所有输出都绑定到另一个bundle的方法,尽管这种方法看上去很方便,但是也存在一系列的缺陷:
- 拆分包(Split Packages) –同一个package中的类来自不同的required bundle,这样的包称之为拆分包。拆分包有以下缺陷:
- 完整性(Completeness) –拆分包是开放式的,没有一种方法可以保证拆分包中是否已经完全包括所有类。
- 有序性(Ordering) –如果相同的类出现在多个required的bundle中,那么对Require- Bundle来说顺序非常重要。错误的排序会导致错误难以跟踪,这类似于传统的classpath模型。
- 性能(Performance) –如果是拆分包,那么类搜索必须要搜索所有的提供者,这样会导致抛出ClassNotFoundException的次数上升,产生额外开销。
-
混乱(Confusing)–很容易找到一些潜在的混乱设置。例如,以下设置是不直观的。
A: Export-Package: p;uses:=q
Import-Package: q
B: Export-Package: q
C: Export-Package: q
D: Require-Bundle: B, C
Import-Package: p
Figure 3.17 Split packages and package constraints
在这个例子中,Bundle D有一个拆分包q来自Bundle B和Bunlde C,然而,Bundle A 导入了包p use:q,Bundle D中也有可见的package p(分别来自BundleB和c),这个关联关系可能产生问题,在特殊情况下,C.q同时在B.q中存在可能就破坏了一致性。
- 导出可变(Mutable Exports) – visibility:=reexport 这一特性可以导致发起requiring的bundle导出特征(export signature)受到被requried bundle导出特征改变的影响,从而发生不可预料的改变。
- 遮蔽(Shadowing) –发起requiring的bundle中的类,可能被requried的bundle中的类遮蔽,这取决于被requried的bundle的导出特征和其中包含的类。(相反的是,在Import- Package中,除非指定resolution:=optional,否则将屏蔽整个export中的包)。
3.14 Bundle片断(Fragment Bundle)
片断(fragment)是指由Framework附加(attach)到宿主bundle(Host bundle)之上的bundle。Attach过程是resolve bundle的一部分:在host bundle解析之前,Framework会将片断bundle的相关定义添加到Host Bundle的定义中,Fragment被认为是Host Bundle的一部分,它们没有自己的类加载器,并且有它们自己的Protection Domain。
Bundle Fragment可以attach到多个同名但不同版本的host中;如果多个同名Bundle片断匹配一个host时,Framework必须只选择其中一个最高版本的片断。
Fragment的一个关键用途是用于提供不同区域的翻译文件,这个可以在应用中实现翻译文件以Bundle的方式独立出来。
当更新已经被attach的Bundle片断时,原先fragment的内容必须attach到host bundle之上,更新的fragment内容只有等到Framework restart或者host bundle更新后才能attach。在这个期间,如果需要attach的fragment有2个版本:旧版本会attach到旧版本的host bundle上,新的fragment bundle能够被attach到新版本或者不一样的host bundle中,这个具体的configuration能够在Bundle Wriring API规范一节中找到。
When attaching a fragment bundle to a host bundle the Framework must perform the following
steps:
当attach一个Fragment到host bundle中,Framework必须按照以下步骤执行:
1.将Fragment中无冲突的import定义添加到host bundle的import定义中。Fragment可以为Host Bundle的private package增加import,这种情况下,host bundle中的private package就被隐藏了。
2.将Fragment中无冲突的Require-Bundle添加到host bundle的Require-Bundle中。
3.将Fragment中无冲突的export定义添加到Host bundle的export定义中。
4.将Fragment中的Provide-Capability添加到Host Bundle的Provide-Capability中.
5.将Fragment中的Require-Capability添加到host bundle的Require-Capability中。
当host和fragment不能resolve出一致的类空间,表示2者之间存在冲突。如果发生冲突,那么Fragment将不会attach到host bundle中。
如果Fragment 成功attach到至少一个host bundle,那么这个Fragment Bundle必须是resolved的状态。
在运行期,fragment的jar文件将在host bundle的类路径搜索之后再搜索,这个在 3.14.2 运行期Fragment一节中有描述。
3.14.1 Fragment-Host
Fragment-Host manifest头描述了链接Host Bundle的Bundle片段。Fragment Host语法如下:
Fragment-Host ::= bundle-description
bundle-description ::= symbolic-name
(';' parameter ) * // See 1.3.2
同时Framework在Fragment-Host中还提供了如下指令:
- extension – 描述了这个扩展是system还是boot classpath扩展。这个指令只有System Bundle中的Fragment-Host才有作用。在3.15 Bundle扩展一节描述了这个值支持以下类型:
- framework –fragment bundle是一个Framework扩展Bundle
- bootclasspath –fragment bundle是一个boot class path的扩展Bundle。 Fragment必须具有所指定实现system bundle的bundle symbolic name或者system.bundle别名。如果bundle的symbolic name和system bundle不相符,那么Framework对扩展Bundle的安装做失败处理。 Framework在Fragment-Host中还提供了以下属性:
- bundle-version –用于选择host bundle的版本范围,默认值为[0.0.0, ∞)。 当fragment bundle解析完成后,Framework必须将Fragment Bundle attach到最高版本的host bundle中。当fragment bundle附加到host bundle上之后,从逻辑上看fragment bundle已成为host bundle的一部分。Fragment中的所有class和resource必须使用host bundle的classloader加载。一个host bundle的所有fragment bundle必须按照fragment的安装顺序进行添加,即按照bundle Id的升序排序。如果在Fragment Bundle attach过程中发生错误,那么Fragment bundle就不能附加到host bundle中,只有当fragment bundle成功attach之后才可以对fragment bundle进行解析。 Host Bundle如果要附加fragment bundle,那么host Bundle必须有BundlePermission[,HOST]。而在fragment bundle中为了可以被attach,fragment bundle必须有BundlePermission[,FRAGMENT]。
3.14.2 运行期Fragment
Fragment中所有的class和resource都是通过host bundle的calssloader处理,而fragment bundle不能有自己的classloader。Fragment bundle被认为是host bundle内在的一部分。
虽然fragment bundle没有自己的classloader,当它不是扩展fragment时,就必须还有一个单独的保护域(Protection Domain)。每一个fragment bundle都可以有一个与自己关联的fragment location和签名。
Host bundle的class path在fragment class path之前进行搜索。这也就是说package可以在host bundle和fragment bundle之间进行拆分。对fragment的查找必须是按照bundle ID升序进行,也也是fragment bundle的安装顺序。
图3.18 Resource/class searching with fragments
图3.18 描述了2个Bundle fragment,bundleB在C之前安装,而B和C都附加在A之中,下面的表格描述了初始化过程中不同package的来源,注意其中的(>)符号。
表3.3 Effect of fragments on searching
在上面的例子中,如果package p从bundle D中导入,那么这个表格将变得完全不同,package p来自bundle D,而Bundle A以及Bundle B的内容将会被忽略。
如果Bundle D中没有package p,那么会搜索class path,而选择了A.q,这是由于A.q > C.q
当host bundle被resolved时,Fragment必须保持附加状态。当host bundle变成unresolved状态时,所有attach过的fragment必须要从host bundle分离。当fragment变为unresolved状态时,Framework必须:
- 将它从附主分离
- 重新解析host bundle
- 重新附加其他的fragment bundle Fragment bundle变为unresolved状态时可以通过回调自己或者refreshPackages method。
3.14.3 fragment bundle中不合法的Manifest Header
以下header不能出现爱fragment bundle中:
- Bundle-Activator
3.15 Bundle扩展
Framework可以有选择的实现部分扩展Bundle,或者在boot class path上提供功能。这些package不能通过一般的导入导出机制来提供。
Boot class path的扩展是必须的,这是因为特定package的实现在它们的boot class path之上或者要对所有的客户端可用。boot classpath扩展的一个例子是java.sql的一个JSR 169。
Framework扩展对于Framework实现来说是必须的,例如,一个Framework的供应商可以通过Framework扩展的bundle提供可选的一些服务(如Permission Admin service、Start Level API)。
扩展Bundle应该使用bundle symbolic name来实现一个system bundle,或者使用同样也是system bundle的system bundle替换。
下面的例子使用了Fragment-Host来为特定的Framework实现来指定一个扩展Bundle:
Fragment-Host: com.acme.impl.framework; extension:=framework
下面的例子使用了Fragment-Host来指定特定的扩展bundle的boot classpath:
Fragment-Host: system.bundle; extension:=bootclasspath
下面的步骤描述了扩展Bundle的生命周期:
1 扩展bundle安装完成之后,进入INSTALLED状态
2 通过Framework判断,扩展bundle可以进入到RESOLVED状态。
3 如果扩展Bundle进行了更新,Framework必须要shutdowm,host虚拟机必须终止,而Framework也要重新启动。
4 如果对一个处在RESOLVED状态的扩展bundle进行更新或者UNINSTALLED,那么就不能再次进去到RESOLVED状态。如果对扩展bundle进行refresh,那么必须关闭Framework、host VM终止、然后重新启动Framework。
这是有效更新bundle的另一种类型,如果旧的扩展bundle被resolved,那么它必须被做为一个fragment附加到system bundle。当这个bundle更新,bundle旧内容必须附加到system bundle,直到system bundle被refresh或者扩展bundle被refresh(使用Wiring API)。当Framework更新新内容,bundle是resolved状态,这时必须启动VM并且重启Framework。
扩展bundle会有普通bundle的所有事件行为。
3.15.1 扩展bundle中的非法manifest header
如果在bundle中指定了以下的头标,那么在扩展bundle安装或者是更新的时候,必将抛出bundle异常(BundleException):
- Import- Package
- Require- Bundle
- Bundle- NativeCode
- DynamicImport- Package
- Bundle- Activator
- Require-Capability (requirements中只有在host里osgi.ee命名空间内的允许定义) 规范允许同时在启动类路径和框架扩展bundle中指定Export- Package。当对扩展bundle解析时,任何由框架扩展bundle指定的导出的包必须由系统bundle来导出。
3.15.2 Class Path处理
Bundle jar文件的扩展启boot classpath必须添加到host vm的boot classpath上。Framework扩展的bundle jar文件需要附加在Framework classpath上。
扩展bundle的classpath的附加顺序按照它们的安装顺序来进行,即按照bundle ID的升序排列。
Framework如果要配置自己以及boot classpath,那么附加的扩展bundle是由具体的实现来完成。在一些运行环境下,可能并不支持扩展bundle。在这样的环境下,如果要安装扩展bundle,那么将会抛出bundle异常。产生的bundle异常有一个标志为UnsupportedOperationException。
3.15.3 可选的Boot classpath扩展
规范中提供了一种可选机制:boot classpath扩展。使用这个可选机制并不会使得实现变得简单,Framework必须使用下面的属性来实现述 boot classpath扩展(这个值是true或者false):
- org.osgi.supports.bootclasspath.extension 如果这个属性没有设置或者这个属性无法识别,那么默认值是false。Framework如果不实现boot classpath扩展,那么必须拒绝安装或者更新bundle,在install或者update时候必须抛出异常。 另外,Framework必须实现fragment,require bundle, 和 extension,通常使用下面的属性设置(true):
- org.osgi.supports.framework.requirebundle
- org.osgi.supports.framework.fragments
- org.osgi.supports.framework.extension
3.16 安全
3.16.1 扩展Bundle
在Java 2安全机制中的Framework环境下允许安装扩展bundle,不过安装之前还需要进行额外的安全检查。为了保证扩展bundle安装成功,Framework必须检查扩展bundle是否拥有分配给它的所有权限(All Permissions)。这也就是说扩展bundle的权限必须要在它安装之前获得。
必须授予扩展bundle的AllPermission权限的原因:这是由于扩展bundle需要在boot classpath或者是Framework实现的保护域(Protection Domain)中加载。这两个保护域都有AllPermission权限。这样,如果一个扩展bundle没有AllPermission权限,那么不允许安装。扩展bundle的安装者必须要有管理权限(AdminPermission[,EXTENSIONLIFECYCLE])来安装扩展bundle。
3.16.2 Bundle权限
大部分的package在包权限管理中共享权限,而fragment和 required bundle通过bundle的symbolic name来进行共享处理。bundle权限就用于这种类型的包共享。bundle权限是可选的,如果Framework支持Require-Bundle,那么也必须要支持bundle的权限。
bundle权限的参数名使用了bundle的symbolic name。symbolic name用于识别目标bundle(target bundle),而且可以在名称后面使用通配符(’.*’ \u002E,\u002A)。
例如,如果fragment A附加到bundle B时,那么A需要BundlePermission("B", "fragment")权限,这样A才允许附加到目标host bundle B。这个指令的动作描述如图3.19:
图 3.19 Permissions and bundle sharing
定义了如下动作:
- provide – 对目标bundle提供package权限。
- require – 从目标bundle中获取package权限。
- host – 附加到目标fragment的权限。
- fragment – 作为fragment附加到host bundle上的权限。 当fragment包含Require-Bundle头时,Framework必须检查fragment保护域的权限。
3.16.3 package权限
bundle只能import或者export有require权限的package。包权限(PackagePermission)必须要用在一个package的所有版本。
包权限由两个参数:
- 可能import或者export的package,可以使用通配符。权限的粒度是针对package而不是package中的类。
- action,IMPORT或者EXPORT。如果bundle有export一个package的权限,那么Framework必须自动授予import这个package的权限。 如果一个包权限的参数为通配符*和EXPORT,那么就允许导入导出任何包。
3.16.4 Resource权限
为了访问以下资源,框架必须授予bundle RESOURCE,METADATA和CLASS的AdminPermission:
- 自身
- 任何附加的fragment
- 导入包中的任何resource bundle中的resource也可以通过使用bundle中特定的方法来访问。这些方法的访问者必须要拥有AdminPermission[bundle,RESOURCE]。
如果访问者没有必需的权限,那么就不能访问resource,并且会返回一个空值。如有权限则返回一个resource的URL对象。这些URL对象称之为bundle resource URL。一旦返回了URL对象后,再对resource进行访问时就不再进行权限检查。URL对象必须使用Framework实现中定义的scheme。
Bundle URL通常由Framework来创建,但在一些情况下,bundle需要通过URL来查找到相关resource,例如,对于和给定Resource处于同一个目录下的Reource,可以创建它的Resource URL。
由于java.net.URL类的设计原因,对于不是Framework创建的Resource URL,它的安全策略略有不同。 并不是所有的URL类构造方法会和URL流处理类(URL Stream Handler)进行交互(实现规范部分)。其它的构造方法至少会调用URL流处理类中的parseURL方法,而且在URL流处理类中会进行安全检查。这种设计使得Framework不可能在构建bundle URL时进行权限检查。
下面的构建方法在构建bundle resource URL时使用parseURL方法,并进行检查:
URL(String spec)
URL(URL context, String spec)
URL(URL context, String spec, URLStreamHandler handler)
当使用上述构造方法创建bundle Resource URL时,Framework的实现必须要在parseURL方法中对调用者进行必要的权限检查。如果没有必需的权限,parseURL方法会抛出异常(Security Exception)。这将导致URL的构造方法抛出一个非正常的URLException。如果调用者有必需的权限,那么可以创建对Resource访问的URL对象,而且以后再也不需要进行检查了。
在下面的构造方法中没有调用parseURL方法,这样在创建URL类期间就不可能进行权限检查:
URL(String protocol, String host, int port, String file)
URL(String protocol, String host, int port, String file, URLStreamHandler handler)
URL(String protocol, String host, String file)
这些构造方法没有进行权限检查就创建了bundle Resource URL,因此对权限的检查就推迟到调用时进行。访问这样创建的URL对象时,如果访问者没有权限(AdminPermission[bundle, RESOURCE])那么Framework就会抛出一个Security Exception。
3.16.5 Capability权限
Capability权限提供一种手段来安全限制访问某种功能,Capability权限是一种基于Permission 的Filter,在Filter Based Permissions一节中有描述,提供了以下附加功能:
- capability.namespace –requirement 或者 provided capability的namespace 这个Filter能够维护目标Bundle的信息,目标bundle总能提供capability,这意味着可以限制从一个特定bundle接受capability。 在一个namespace下的Capabilities,提供了没有权限不可访问其他bundle的能力,而且在namespace中没有权限就不能满足Bundle的Requirement。
Capability Permission有以下行为:
- REQUIRE – 给定命名空间的权限需求,目标bundle能够通过filter提供capability.
- PROVIDE –在指定命名空间下提供capability,目标bundle会检查权限. Capability Permission有如下构造函数:
- CapabilityPermission(String,String) – 构造函数设置filter和action.此构造函数还用于验证provide action.
- CapabilityPermission(String,Map,Bundle,String) – 为了对namespace验证权限提供了特殊构造函数. Bundle参数是指provide capability的bundle。
3.16.5 权限检查
由于多个bundle会导出具有相同类名的权限类,Framework必须要保证权限检查时使用了正确的类。例如,调用checkPermission方法提供了权限类的接口:
void foo(String name) {
checkPermission(new FooPermission(name,"foo"));
}
权限接口类来自于独特的途径,权限只能用相同来源的实例来测试。
因此,Framework需要基于类而不是类名的方式来查找权限。如果需要实例化一个权限,那么必须要检查该实例的权限类。这对Framework的实现来说很复杂,但是不会影响到bundle的开发人员。
考虑如下示例:
Bundle A
Import-Package: p
Export-Package: q
Bundle B
Import-Package: p
bundle A使用p.FooService,使用这个类来检查q.FooPermission当调用它的任何方法时。
bundle B在其保护域中的权限信息对象中有一个FooPermission。
bundle B调用bundle A中FooService中的方法。
FooService通过使用一个新的FooPermission接口来调用checkPermission方法。
在调用FooPermission中的方法之前,Framework必须使用来自同一个类加载器中的FooPermission对象作为给定的FooPermission对象。在这种情况下,FooPermission类来自包A.q。
权限检查完毕之后,bundle B就有了一个FooPermission实例,这个实例使用了没有导入的包中类的。因此,Framework需要实例化多种不同FooPermission类来满足不同的bundle需求。
3.17 Changes
- Requirement/Capability模型变化
- Filter类中增加static valueOf 方法
- 扩展Bundle-RequiredExecutionEnvironment 描述和osgi.ee命名空间
- 增加VersionRange类
- 对扩展bundle中不合法的Manifest header增加额外的header
3.18 参考
[1] Java Virtual Machine Specification, Second Edition
http://docs.oracle.com/javase/specs/jvms/se5.0/html/VMSpecTOC.doc.html
[2] The Standard for the Format of ARPA Internet Text Messages
STD 11, RFC 822, UDEL, August 1982
http://www.ietf.org/rfc/rfc822.txt
[3] The Hypertext Transfer Protocol - HTTP/1.1
RFC 2068 DEC, MIT/LCS, UC Irvine, January 1997
http://www.ietf.org/rfc/rfc2068.txt
[4] The Java Language Specification, Second Edition, Sun Microsystems, 2000
http://docs.oracle.com/javase/specs/
[5] A String Representation of LDAP Search Filters
RFC 1960, UMich, 1996
http://www.ietf.org/rfc/rfc1960.txt
[6] The Java Security Architecture for JDK 1.2
Version 1.0, Sun Microsystems, October 1998
[7] The Java 2 Package Versioning Specification
http://docs.oracle.com/javase/1.4.2/docs/guide/versioning/index.html
[8] Codes for the Representation of Names of Languages
ISO 639, International Standards Organization
http://lcweb.loc.gov/standards/iso639-2/langhome.html
[9] Zip File Format
The Zip file format as defined by the java.util.zip package.
[10] Manifest Format
http://docs.oracle.com/javase/1.4.2/docs/guide/jar/jar.html#JAR%20Manifest
[11] W3C EBNF
http://www.w3c.org/TR/REC-xml#sec-notation
[12] Mathematical Convention for Interval Notation
http://planetmath.org/encyclopedia/Interval.html
References Module Layer Framework API
Page 78 OSGi Core Release 5
[13] Uniform Resource Identifiers URI: Generic Syntax
RFC 2396
http://www.ietf.org/rfc/rfc2396.txt
[14] Codes for the Representation of Names of Languages
ISO 639, International Standards Organization
http://lcweb.loc.gov/standards/iso639-2/langhome.html
[15] OSGi IANA Mime Type
http://www.iana.org/assignments/media-types/application/vnd.osgi.bundle
[16] OSGi Header Namespace Registry
http://www.osgi.org/headers
[17] Portable Network Graphics (PNG) Specification (Second Edition)
http://www.w3.org/TR/2003/REC-PNG-20031110/
[18] Open Source Initiative
http://www.opensource.org/
[19] OSGi Semantic Versioning
http://www.osgi.org/wiki/uploads/Links/SemanticVersioning.pdf
[20] Specification References
http://www.osgi.org/Specifications/Reference
[21] Google Android
http://developer.android.com/index.html
[22] Google App Engine
http://developer.android.com/index.html
[23] Google Web Toolkit
http://code.google.com/webtoolkit/