3.7 Resolving Process
Resolving is the process that creates a wiring between bundles. Constraints on the wires are statically defined by:
• Import and export packages (the DynamicImport-Package header is ignored in this phase)
• Required bundles, which import all exported packages from a bundle as defined in Requiring Bundles on page 65.
• Fragments, which provide their contents and definitions to the host as defined in Fragment Bundles on page 68
解析是bundle间建立连接的过程。连接上的约束的定义来自:
• 引入和输出包(头DynamicImport-Package在这个阶段被忽略)
• Required bundles,从一个bundle那引入所有输出包
• 片段,提供它们的内容和定义到宿主bundle。
Before a bundle is resolved, all its Fragments must be attached. The resolving process is then a constraint-solving algorithm that can be described in terms of requirements on wiring relations. The resolving process is an iterative process that searches through the solution space.
If a module has both import and export definitions for the same package, then the Framework needs to decide which to choose. It must first try to resolve the overlapping import definition. The following outcomes are possible:
• External – If this resolves to an export statement in another bundle, then the overlapping export definition in this bundle is discarded.
• Internal – If it is resolved to an export statement in this module, then the overlapping import definition in this module is discarded.
• Unresolved – There is no matching export definition. This is however a developer error because it means the overlapping export definition of the bundle is not compatible with the overlapping import definition.
bundle被解析之前,它所有的片段必须被附加上。这时解析过程则是一个根据连接关系需求描述成的解析约束法则。解析过程是个搜索溶解空间的交互过程。
如果一个模块对同一个包都有引入和输出定义,框架需要决定选择哪一个定义,必须首先尝试解析多重引入定义。可能会有以下结果:
• External – 如果将其解析到(选择)另一个bundle的输出声明,那么这个bundle的多重输出声明将被放弃。
• Internal – 如果他被解析到(选择)当前bundle的输出定义,那么这个多重引入定义被放弃。
• Unresolved – 没有匹配的输出定义。这是开发者的错误,因为它表示这个bundle的多重输出定义与多重引入定义不一致(同一个模块下,一个包的引入定义找不到本模块声明的输出定义)。
A bundle can be resolved if the following conditions are met:
• All its mandatory imports are wired
• All its mandatory required bundles are available and their exports wired A wire is only created when the following conditions are met:
• The importer’s version range matches the exporter’s version. See Version Matching on page 41.
• The importer specifies all mandatory attributes from the exporter. See Mandatory Attributes on page 45.
• All the importer’s attributes match the attributes of the corresponding exporter. See Attribute Matching on page 45
• Implied packages referring to the same package as the wire are wired to the same exporter. See Package Constraints on page 43.
• The wire is connected to a valid exporter.
The following list defines the preferences, if multiple choices are possible, in order of decreasing priority:
• A resolved exporter must be preferred over an unresolved exporter.
• An exporter with a higher version is preferred over an exporter with a lower version.
• An exporter with a lower bundle ID is preferred over a bundle with a higher ID.
如果满足以下条件,一个bundle会被解析:
• 它所有的强制引入被连接
• 它的强制需求bundles都可用,并且这些bundles的输出连接A的连接当满足以下条件时被创建:
• 引入者的版本范围匹配输出者的版本
• 引入者指定了所有输出定义的强制属性
• 所有引入者的属性匹配相应的输出者的属性
• 暗指包引用同一个包,连接被连接到同一个输出者。
• 连接被连接到可用的输出者
如果多个选择可用时,下面的列表定义了优先权,优先权顺序递减
• 一个解析的输出者必须优先于未解析输出者
• 一个版本高的输出者优先于低版本
• 低ID的bundle优先于高ID的bundle
3.8 Runtime Class Loading
Each bundle installed in the Framework must not have an associated class loader until after it is resolved. After a bundle is resolved, the Framework must create one class loader for each bundle that is not a fragment. The framework may delay creation of the class loader until it is actually needed.
One class loader per bundle allows all resources within a bundle to have package level access to all other resources in the bundle within the same package. This class loader provides each bundle with its own name space, to avoid name conflicts, and allows resource sharing with other bundles.
This class loader must use the wiring as calculated in the resolving process to find the appropriate exporters. If a class is not found in the imports, additional headers in the manifest can control the searching of classes and resources in additional places.
The following sections define the factors that influence the runtime class loading and then define the exact search
安装在框架中的每一个bundle必须不能有一个关联的class loader,直到这个bundle被解析之后。一个bundle被解析之后,框架必须为每一个bundle创建一个class loader,而不是片段。框架可能会延迟class loader的生成,直到它真正被需要。
一个bundle的class loader允许这个bundle中所有的资源得到对其他所有这个bundle中同一个package中的资源的包级别访问权限。这个class loader为bundle提供它自己的名字空间,用于避免名字冲突,允许资源共享到其他bundles。
class loader必须使用与在解析过程中一样的连接去查找合适的输出者。如果一个类在引入者中找不到,manifest中附加的头可以控制在附加的空间中对类和资源的查找。
一下章节定义了影响运行时类加载的因素,然后定义了精确查找
3.8.1 Bundle Class Path
Intra bundle class path dependencies are declared in the Bundle-Classpath manifest header. This declaration allows a bundle to declare its embedded class path using one or more JAR files or directories that are contained in the bundle’s JAR file.
The Bundle-Classpath manifest header is a list of comma-separated file names. A file name can be either:
• The dot (’.’ \u002E), representing the bundle’s JAR file itself, is the default value if no Bundle-Classpath is specified.
• A path to a JAR file contained in the bundle’s JAR file.
• A path to a directory contained in the bundle’s JAR file.
The Bundle-Classpath manifest header must conform to the following syntax:
bundle内部的类路径依赖关系被声明在manifest头Bundle-Classpath中。这个声明允许一个bundle使用一个或多个包含在bundle的JAR文件中的JAR文件或目录去声明它的内部的类路径。
头Bundle-Classpath是一个逗号分隔的文件名列表。一个文件名可以是以下内容:
• 点,描述bundle的JAR文件自己,默认值。
• 包含在bundle的JAR文件中的一个JAR文件路径
• 包含在bundle的JAR文件中的一个目录的路径
头Bundle-Classpath必须符合下面的语法:
Bundle-Classpath::= entry ( ’,’ entry )*
entry ::= target ( ’;’ target )*
( ’;’ parameter ) *
target ::= path | ’.’ // See 1.3.2
The Framework must ignore any unrecognized parameters.
The Framework must ignore a target in the Bundle-Classpath header if the target (directory or JAR file) cannot be located when it is needed, which can happen at any time after the bundle is resolved. However, in this case the Framework should publish a Framework Event of type INFO with an appropriate message for each entry that cannot be located.
When locating a class path entry in a bundle, the Framework must attempt to locate the class path entry relative to the root of the bundle’s JAR. If a class path entry cannot be located in the bundle, then the Framework must attempt to locate the class path entry in each of the attached fragment bundles.
The attached fragment bundles are searched in ascending bundle ID order. This allows a fragment to supply entries that are inserted into the host's Bundle-Classpath
The following example illustrates this:
框架必须忽略所有未经承认的参数。
框架必须忽略头Bundle-Classpath中的target,如果当需要的时候这个target(目录或JAR文件)不能被找到,这个忽略可以发生在bundle被解析后的任何时间。尽管如此,在这种情况下,框架应该发布一个类型为INFO的事件,为每一个不能定位的entry生成一条合适的消息。
当在bundle中定位一个类路径实体的时候,框架必须尝试定位相对于bundle的JAR文件的根路径的类路径实体。如果在bundle一个类路径不能被定位,那么框架必须尝试定位每一个附加片段bundles中的类路径实体。
附加片段bundles通过bundle ID的升序来查找。这就允许了片段提供宿主bundle的头Bundle-Classpath中插入的实体。
请看下面是个例子:
A: Bundle-SymbolicName: A
Bundle-Classpath: required.jar,optional.jar,default.jar
content
required.jar
default.jar
B: Bundle-SymbolicName: B
Bundle-Classpath: fragment.jar
Fragment-Host: A
content
optional.jar
fragment.jar
In this example, bundle A has a Bundle-Classpath header with three entries (required.jar, optional.jar, and default.jar). The required.jar class path entry may contain the classes and resources that must be present for the bundle to function. The optional.jar class path entry may contain classes and resources that the bundle will use if present.
The default.jar class path entry may contain classes and resources that the bundle will use if the optional.jar is not available, but the classes and resources from default.jar can be overridden by classes and resources in the optional.jar (from the fragment) class path entries. Bundle A has only the required.jar and default.jar entries packaged with it. This allows a fragment bundle B to be installed that can supply the optional.jar for bundle A.
The fragment bundle B has a Bundle-Classpath with one entry (fragment. jar). When bundle A is resolved and the fragment bundle B is attached then the bundle class path for the bundle A is:
在这个例子中,bundle A的头Bundle-Classpath有3个实体(required.jar, optional.jar, and default.jar)。required.jar类路径实体可能包含必须提供给bundle的功能的类和资源。optional.jar类路径实体可能包含如果提供,bundle会使用到的类和资源(例如logging)。
default.jar类路径实体可能包含如果optional.jar不可用,那么bundle可能会用到的类和资源,但是default.jar中的类和资源能被optional.jar(片段bundle中)中的类和资源重载。bundle A中只打包了required.jar和default.jar实体,这允许片段bundle B被安装,为bundle A提供optional.jar。
片段bundle B头Bundle-Classpath有一个实体(fragment. jar)。当bundle A被解析,片段bundle B被附加时,bundle A的类路径则成为:
required.jar, optional.jar, default.jar, fragment.jar
3.8.2 Dynamic Import Package
Dynamic imports are matched to export definitions (to form package wirings) during class loading, and therefore do not affect module resolution.
Dynamic imports apply only to packages for which no wire has been established and no definition could be found in any other way. Dynamic import is used as last resort.
动态引入在类加载期间被匹配到输出定义(用于构成包连接),因此不会影响到模块的解析。
动态引入仅仅适用于没有被连接和无法从其他方式获得定义的包。动态引入是最后的手段。
DynamicImport-Package ::= dynamic-description
( ',' dynamic-description )*
dynamic-description::= wildcard-names ( ';' parameter )*
wildcard-names ::= wildcard-name ( ';' wildcard-name )*
wildcard-name ::= package-name
| ( package-name '.*' ) // See 1.3.2
| '*'
No directives are architected by the Framework for DynamicImport-Package.
Arbitrary matching attributes may be specified. The following arbitrary matching attributes are architected by the Framework:
• version -- A version range to select the version of an export definition. The default value is 0.0.0 .
• bundle-symbolic-name – The bundle symbolic name of the exporting bundle.
• bundle-version – a version range to select the bundle version of the exporting bundle. The default value is 0.0.0.
Packages may be named explicitly or by using wild-carded expressions such as org.foo.* and *. The wildcard can stand for any suffix, including multiple sub-packages.
Dynamic imports must be searched in the order in which they are specified.
The order is particularly important when package names with wildcards are used. The order will then determine the order in which matching occurs.
This means that the more specific package specifications should appear before the broader specifications. For example, the following DynamicImport- Package header indicates a preference for packages supplied by ACME:
框架不必为DynamicImport-Package创建指令,可以指定专有匹配属性,一下专有匹配属性由框架给定:
• version -- 一个版本范围,用于选择输出定义的版本。默认值是0.0.0
• bundle-symbolic-name – 输出bundle的标记名
• bundle-version – 一个版本范围,用于选择输出bundle的版本。默认值是0.0.0
packages能被明确指定,或使用通配符表达式,它能代替任何后缀,包括多个sub-packages。
动态引入必须在指定的顺序下查找包。
当包名使用的是通配符时,这个顺序显得尤为重要。这时,这个顺序将决定发生匹配的顺序。
也就是说指定的包规范应该更多的出现在扩展规范之前。例如,下面这个头DynamicImport- Package表示优先选择由ACME提供的包
DynamicImport-Package: *;vendor=acme, *
If multiple packages need to be dynamically imported with identical parameters, the syntax permits a list of packages, separated by semicolons, to be specified before the parameters.
During class loading, the package of the class being loaded is compared against the specified list of (possibly wild-carded) package names. Each matching package name is used in turn to attempt to wire to an export using the same rules as Import-Package. If a wiring attempt is successful (taking any uses constraints into account), the search is forwarded to the exporter’s class loader where class loading continues. The wiring must not subsequently be modified, even if the class cannot be loaded. This implies that once a package is dynamically resolved, subsequent attempts to load classes or resources from that package are treated as normal imports.
如果多个包需要被以相同的参数引入,这个语法允许一个包列表,以分号隔开,指定在参数之前。
类加载期间,被加载的类的包被与指定的包名的列表(或通配符)比较,每一个匹配的包名轮流尝试按照Import-Package的规则连接到一个输出。如果一个尝试连接成功(按照uses约束),当继续加载类时,查找会被定位到输出者的class loader。之后,这个连接必须不能被更改,即使随后的类不能被加载。也就是说一旦一个包是被动态解析的,那么随后尝试从这个包中加载类或资源将被视为普通引入。
In order for a DynamicImport-Package to be resolved to an export statement, all attributes of the dynamic import definition must match the attributes of the export statement. All mandatory arbitrary attributes (as specified by the exporter, see Mandatory Attributes on page 45) must be specified in the dynamic import definition and match.
Once a wire is established, any uses constraints from the exporter must be obeyed for further dynamic imports.
Dynamic imports are very similar to optional packages, see Optional Packages on page 42, but differ in the fact that they are handled after the bundle is resolved.
为了使一个动态引入包被解析到一个输出声明,所有动态引入定义中的属性必须匹配输出声明中的属性,所有输出声明中的强制专有属性必须在动态引入定义中指定并匹配。
一旦一个连接被产生,输出者中所有uses约束必须被动态引入者遵循。
动态引入与可选包非常相似,但是实际上他们区别于bundle被解析之后才被处理。
3.8.3 Parent Delegation
The Framework must always delegate any package that starts with java. to the parent class loader.
Certain Java virtual machines, also SUN’s VMs, appear to make the erroneous assumption that the delegation to the parent class loader always occurs. This implicit assumption of strictly hierarchical class loader delegation can result in NoClassDefFoundErrors. This happens if the virtual machine implementation expects to find its own implementation classes from any arbitrary class loader, requiring that packages loaded from the boot class loader not be restricted to only the java.* packages.
Other packages that must be loaded from the boot class loader can therefore be specified with the System property:
框架必须总是代理以java开头的包到parent class cloader。
显然JVM做了一个错误的假设,到parent class cloader的代理总是会发生。而这个严格等级的class loader代理的所隐藏的假设,会导致NoClassDefFoundErrors。如果虚拟机实现希望从所有专有class loader中查找它自己的实现类,它需要的包是从boot class loader中加载的,而不仅仅局限于java.*这样的包。
因此,其他必须从boot class loader加载的包能被指定到以下系统属性:
org.osgi.framework.bootdelegation
This property must contain a list with the following format:
org.osgi.framework.bootdelegation ::= boot-description
( ',' boot-description )*
boot-description::= package-name // See 1.3.2
| ( package-name '.*' )
| '*'
The .* wildcard means deep matching. Packages that match this list must be loaded from the parent class loader. The java.* prefix is always implied; it does not have to be specified.
The single wildcard means that the Framework must always delegate to the parent class loader first, which is the same as the Release 3 behavior. For example, when running on a SUN JVM, it may be necessary to specify a value like:
通配符.*表示深层匹配。匹配这个列表的包必须被从parent class loader中加载。前缀java.*总是隐含着;而不需要指定。单个通配符表示框架必须总是首先代理到parent class loader,与版本3一样。例如,当运行于sun jvm时,它可能有必要指定一个如下的值:
org.osgi.framework.bootdelegation=sun.*,com.sun.*
With such a property value, the Framework must delegate all java.*, sun.*, and com.sun.* packages to the parent class loader.
对于这样的值,框架必须代理所有java.*, sun.*, 和 com.sun.*的包到parent class loader。
3.8.4 Overall Search Order
Frameworks must adhere to the following rules for class or resource loading. When a bundle’s class loader is requested to load a class or find a resource, the search must be performed in the following order:
框架必须遵循以下规则来加载类或资源。当一个bundle的class loader被请求加载类或查找资源时,必须按照以下顺序来执行:
1 If the class or resource is in a java.* package, the request is delegated to the parent class loader; otherwise, the search continues with the next step. If the request is delegated to the parent class loader and the class or resource is not found, then the search terminates and the request fails.
1. 如果类或资源在一个java.*的包中,这个请求被代理到parent class loader,否则,进入下一步。如果请求被代理到parent class loader,而类或资源却没有找到,那么查找被中断,请求失败。
2 If the class or resource is from a package included in the boot delegation list (org.osgi.framework.bootdelegation), then the request is delegated to the parent class loader. If the class or resource is found there, the search ends.
2. 如果类或资源来自一个包含在boot代理列表中的包,那么这个请求被代理到parent class loader。如果类或资源被找到,那么请求结束。
3 If the class or resource is in a package that is imported using Import-Package or was imported dynamically in a previous load, then the request is delegated to the exporting bundle’s class loader; otherwise the search continues with the next step. If the request is delegated to an exporting class loader and the class or resource is not found, then the search terminates and the request fails.
3. 如果类或资源是在一个使用Import-Package引入,或是前面的加载中动态引入的包中,那么请求将被代理到输出bundle的class loader。否则进入下一步。如果请求被代理到一个输出bundle的class loader,类或资源没有找到,那么查找中断,请求失败。
4 If the class or resource is in a package that is imported from one or more other bundles using Require-Bundle, the request is delegated to the class loaders of the other bundles, in the order in which they are specified in this bundle’s manifest. This entails a depth-first strategy; all required bundles are searched before the bundle classpath is used. If the class or resource is not found, then the search continues with the next step.
4. 如果类或资源是在一个使用Require-Bundle从一个或多个其他bundles引入的包中,这个请求将被代理到这些bundles的class loader,按照manifest中指定的顺序。这确保了深度优先策略;所有required bundles在bundle类路径使用之前被查找。如果类或资源没有找到,进入下一步。
5 The bundle’s own internal bundle class path is searched. If the class or resource is not found, then the search continues with the next step.
5. 查找bundle自己的内部类路径。如果资源或类没有找到,进入下一步。
6 Each attached fragment’s internal bundle class path is searched. The fragments are searched in ascending bundle ID order. If the class or resource is not found, then the search continues with the next step.
6. 查找附加片段的内部bundle类路径,查找顺序根据bundle ID的升序,如果没有找到,进入下一步。
7 If the class or resource is in a package that is exported by the bundle or the package is imported by the bundle (using Import-Package or Require-Bundle), then the search ends and the class or resource is not found.
7. 如果类或资源是在一个被片段bundle输出的包中,或者这个包被片段bundle(使用Import-Package or Require-Bundle)引入,那么查找终止,类或资源无法被找到。
8 Otherwise, if the class or resource is in a package that is imported using DynamicImport-Package, then a dynamic import of the package is now attempted. An exporter must conform to any implied package constraints. If an appropriate exporter is found, a wire is established so that future loads of the package are handled in Step 3. If a dynamic wire is not established, then the request fails.
8. 否则,如果类或资源是在一个使用DynamicImport-Package引入的包中,那么包的动态引入被附加。一个输出者必须遵循所有的暗指包约束。如果一个合适的输出者被找到,一个连接被创建,然后包的加载在步骤3中被处理。如果一个动态连接没有被创建,那么请求失败。
9 If the dynamic import of the package is established, the request is delegated to the exporting bundle’s class loader. If the request is delegated to an exporting class loader and the class or resource is not found, then the search terminates and the request fails.
9. 如果包的动态引入被创建,请求被代理到输出bundle(片段bundle)的class loader。如果类或资源没有找到,查找失败。
When delegating to another bundle class loader, the delegated request enters this algorithm at Step 4.
The following non-normative flow chart illustrates the search order described above:
3.8.5 Parent Class Loader
The set of implicitly imported packages are all java.* packages, since these packages are required by the Java runtime, and using multiple versions at the same time is not easy. For example, all objects must extend the same Object class.
A bundle must not declare imports or exports for java.* packages; doing so is an error and any such bundle must fail to install. All other packages available through the parent class loader must be hidden from executing bundles.
However, the Framework must explicitly export relevant packages from the parent class loader.
The system property
暗指包是所有java.*包,因为这些包是JAVA运行所需。在同一时间使用多个版本并不容易,例如,所有的对象必须继承同一个类Object
一个bundle必须不能为包java.*声明输出或引入;这么做是一个错误并且凡是这样做的bundle都必须安装失败。所有其他对parent class loader可用的包必须被隐藏到执行bundles。
可是,框架必须输出parent class loader相关的包。
系统属性
org.osgi.framework.system.packages
contains the export packages descriptions for the system bundle. This property employs the standard Export-Package manifest header syntax:
包含了描述系统bundle的输出包。它使用标准Export-Package头语法
org.osgi.framework.system.packages ::= package-description (
',' package-description )*
Some classes on the boot class path assume that they can use any class loader to load other classes on the boot class path, which is not true for a bundle class loader. Framework implementations should attempt to load these classes from the boot class path.
The system bundle (bundle ID zero) is used to export non-java.* packages from the parent class loader. Export definitions from the system bundle are treated like normal exports, meaning that they can have version numbers, and are used to resolve import definitions as part of the normal bundle resolving process. Other bundles may provide alternative implementations of the same packages.
The set of export definitions for the parent class loader can either be set by this property or calculated by the Framework. The export definitions must have the implementation specific bundle symbolic name and version value of the system bundle.
Exposing packages from the parent class loader in this fashion must also take into account any uses directives of the underlying packages. For example, the definition of javax.crypto.spec must declare its usage of
javax.crypto.interfaces and javax.crypto.
一些boot class path中的类假设为他们可以使用任何class loader去加载boot class path中的其他类,对于一个bundle的class loader这时不对的。框架应该尝试从boot class path加载这些类。
系统bundle(ID是0)用于从parent class loader中输出非java.*的包。系统bundle中的输出定义被视为常规输出,也就是说它们能有版本号,用于解析引入定义,作为常规解析的一部分。其他bundles可以提供对同一个包作为选择的实现。
parent class loader的输出定义能被这个属性设置或是通过框架决定。输出定义必须有实现系统bundle的特定bundle标记名和版本号。
通过这个方式从parent class loader中暴露(输出)的包必须考虑到这些包的uses指令。例如,javax.crypto.spec的定义必须声明它的
javax.crypto.interfaces 和 javax.crypto.的用法
3.8.6 Resource Loading
A resource in a bundle can be accessed through the class loader of that bundle but it can also be accessed with the getResource, getEntry or findEntries methods. All these methods return a URL object or an Enumeration object of URL objects. The URLs are called bundle entry URLs. The schemes for the URLs returned by these methods can differ and are implementation dependent.
Bundle entry URLs are normally created by the Framework, however, in certain cases bundles need to manipulate the URL to find related resources. The Framework is therefore required to ensure that:
一个bundle中的资源可以通过这个bundle的class loader,它同样能被方法getResource, getEntry 或 findEntries访问到。所有这些方法都返回一个URL对象或一个URL对象的Enumeration对象。URLs 被称为bundle实体URLs。
bundle实体URLs通常是由框架生成,但是无论如何都是通过操作URL找到相关资源。因此框架需要确保:
• Bundle entry URLs must be hierarchical (See [32] Uniform Resource Identifiers URI: Generic Syntax)
• Usable as a context for constructing another URL.
• The java.net.URLStreamHandler class used for a bundle entry URL must be available to the java.net.URL class to setup a URL that uses the protocol scheme defined by the Framework.
• The getPath method for a bundle entry URL must return an absolute path (a path that starts with '/') to a resource or entry in a bundle. For example, the URL returned from getEntry("myimages/test.gif") must have a path of /myimages/test.gif.
• bundle实体URLs必须是分等级的。
• 对构造其他URL的context可用。
• 使用于bundle entry URL的类java.net.URLStreamHandler必须对类java.net.URL可用,用于设置一个使用框架定义的协议摘要的URL。
• 用于一个bundle entry URL的方法getPath必须返回一个bundle中的资源或实体的绝对路径,
For example, a class can take a URL to an index.html bundle resource and map URLs in this resource to other files in the same JAR directory.
public class BundleResource implements HttpContext {
URL root; // to index.html in bundle
URL getResource( String resource ) {
return new URL( root, resource );
}
}
3.8.7 Bundle Cycles
Multiple required bundles can export the same package. Bundles which export the same package involved in a require bundle cycle can lead to lookup cycles when searching for classes and resources from the package.
Consider the following definitions:
多个必须的bundle能输出同一个包。输出同一个包的bundles包含了一个bundle循环,能循环查找包中的类和资源。
考虑下面的定义
A: Require-Bundle: B, C
C: Require-Bundle: D
These definitions are depicted in Figure 3.19.
Each of the bundles exports the package p. In this example, bundle A requires bundle B, and bundle C requires bundle D. When bundle A loads a class or resource from package p, then the required bundle search order is the following: B, D, C, A. This is a depth first search order because required bundles are searched before the bundle classpath is searched (see step 4).
The required bundles are searched in the order that they appear in the Require-Bundle header. The depth first search order can introduce endless search cycles if the dependency graph has a cycle in it.
Using the previous setup, a cycle can be introduced if bundle D requires bundle A as depicted in Figure 3.20.
他们都输出包p。在这个例子中,bundle A需要bundle B,和C,bundle C需要bundle D.当bundle A从包p中加载一个类或资源时,查找顺序则为:B,D,C,A. 这时一个深层有限查找顺序,因为required bundles先于本bundle的classpath被查找。
required bundles被查找的顺序按照Require-Bundle头中出现的顺序。深层有限查找顺序能陷入无限查找循环,如果里面的依赖图是循环的话。
D: Require-Bundle: A
When the class loader for bundle A loads a class or resource from package p then the bundle search order would be the following: B, B, B,... if cycles were not taken into account.
Since a cycle was introduced each time bundle D is reached the search will recurs back to A and start over. The framework must prevent such dependency cycles from causing endless recursive lookups.
To avoid endless looping, the Framework must mark each bundle upon first visiting it and not explore the required bundles of a previously visited bundle. Using the visited pattern on the dependency graph above will result in the following bundle search order: B, D, C, A.
当bundle A的class loader从包p加载一个类或资源时,bundle查找顺序将变成:B,B,B,...如果不考虑循环。
因为每次循环到bundle D的时候,查找将会返回到A并重新开始。框架必须防止这种依赖循环导致的无限递归查找。
要避免无限循环,框架必须标记每个bundle第一次访问,并且不会访问先前访问过的bundle的required bundles。 将这个模式使用在上面的依赖图中,将是查找顺序变为:B,D,C,A.
3.8.8 Code Executed Before Started
Packages exported from a bundle are exposed to other bundles as soon as the bundle has been resolved. This condition could mean that another bundle could call methods in an exported package before the bundle exporting the package is started.
一旦一个bundle被解析,它输出的包将暴露给其他bundles。也就是说输出了包的bundle启动之前,其他bundle就能调用这个包中的方法了。
3.9 Loading Native Code Libraries
When a class loaded by a bundle's class loader attempts to load a native library, by calling System.loadLibrary, the findLibrary method of the bundle’s class loader must be called to return the file path in which the Framework has made the requested native library available. The parameter to the findLibrary method is the name of the library in operating system independent form, like http. The bundle class loader can use the mapLibraryName method from the VM to map this name to an operating system dependent name, like libhttp.so.
当一个被bundle的class loader加载了的类尝试使用System.loadLibrary加载本地库时,bundle的class loader的findLibrary方法必须被调用,用于返回文件路径,框架已经使其可用。findLibrary方法的参数是操作系统中独立库的名字,例如http。这个bundle的class loader可以使用VM的方法mapLibraryName将这个名字映射到由操作系统决定的名字,就像libhttp.so。
The bundle's class loader must attempt to find the native library by examining the selected native code clauses, if any, of the bundle associated with the class loader and each attached fragment. Fragments are examined in ascending bundle ID order. If the library is not referenced in any of the selected native code clauses then null must be returned which allows the parent class loader to search for the native library.
The bundle must have the required RuntimePermission[loadLibrary.<library name>] in order to load native code in the OSGi Service Platform.
The Bundle-NativeCode manifest header must conform to the following syntax:
Bundle-NativeCode ::= nativecode
( ',' nativecode )* ( ’,’ optional) ?
nativecode ::= path ( ';' path )* // See 1.3.2
( ';' parameter )+
optional ::= ’*’
When locating a path in a bundle the Framework must attempt to locate the path relative to the root of the bundle that contains the corresponding native code clause in its manifest header.
The following attributes are architected:
• osname – Name of the operating system. The value of this attribute must be the name of the operating system upon which the native libraries run. A number of canonical names are defined in Environment Properties on page 93.
• osversion – The operating system version. The value of this attribute must be a version range as defined in Version Ranges on page 28.
• processor – The processor architecture. The value of this attribute must be the name of the processor architecture upon which the native libraries run. see Environment Properties on page 93.
• language – The ISO code for a language. The value of this attribute must be the name of the language for which the native libraries have been localized.
• selection-filter – A selection filter. The value of this attribute must be a filter expression that indicates if the native code clause should be selected or not.
The following is a typical example of a native code declaration in a bundle's manifest:
Bundle-NativeCode: lib/http.dll ; lib/zlib.dll ;
osname = Windows95 ;
osname = Windows98 ;
osname = WindowsNT ;
processor = x86 ;
selection-filter=
"(com.acme.windowing=win32)";
language = en ;
language = se ,
lib/solaris/libhttp.so ;
osname = Solaris ;
osname = SunOS ;
3.10 Localization
A bundle contains a significant amount of information that is human-readable. Some of this information may require different translations depending on the user's language, country, and any special variant preferences, a.k.a. the locale. This section describes how a bundle can provide common translations for the manifest and other configuration resources depending on a locale.
Bundle localization entries share a common base name. To find a potential localization entry, an underscore (’_’ \u005F) is added plus a number of suffixes, separated by another underscore, and finally appended with the suffix .properties . The suffixes are defined in java.util.Locale.
The order for the suffixes this must be:
• language
• country
• variant
For example, the following files provide manifest translations for English, Dutch (Belgium and the Netherlands) and Swedish.
一个bundle包含一个长幅的可读性信息。这些信息可能需要根据用户语言,国家和任何指定的变量参数(也叫做locale)的不同来进行转换。本节描述了一个bundle怎样根据一个locale来提供一个普通的转换给manifest和其他配置资源。
bundle本地化实体共享一个基本的普通名字。要找到潜在的本地化实体,会有一个下划线加上一个后缀,由另一个下划线分隔,最终以后缀.properties结束。这个后缀定义在java.util.Locale。
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
The Framework searches for localization entries by appending suffixes to the localization base name according to a specified locale and finally appending the .properties suffix. If a translation is not found, the locale must be made more generic by first removing the variant, then the country and finally the language until an entry is found that contains a valid translation.
框架查找本地化实体,通过根据指定的locale 添加后缀到本地化基础名,最后添加后缀.properties。如果一个转换没有找到,locale必须通过删除第一个变量,接着是国家,最后是语言,从而变得更通用,直到一个包含了可用转换的实体被发现。
For example, looking up a translation for the locale en_GB_welsh will search in the following order:
例如,查找顺序如下:
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
This allows localization files for more specific locales to override localizations from less specific localization files.
3.10.1 Finding Localization Entries
Localization entries can be contained in the bundle or delivered in fragments. The Framework must therefore first look in the bundle and then in its attached fragments. Fragment bundles must delegate the search for a localization entry to their host bundle with the lowest bundle ID.
The bundle's class loader is not used to search for localization entries. Only the contents of the bundle and its attached fragments are searched. The bundle will still be searched for localization entries even if dot ('.') is not in the bundle class path.
本地化实体可以被包含在bundle中,或放在片段中。因此框架必须首先查看bundle,然后再看它的片段。片段bundle必须代理它的最小ID的宿主bundle对本地化实体的查找。
bundle的class loader不是用来查找本地化实体的。仅仅是bundle的内容和它的片段被查找。即使.不在bundle的类路径中,bundle将仍然会被查找本地化实体。
3.10.2 Manifest Localization
Localized values are stored in property resources within the bundle. The default base name of the bundle localization property files is OSGI-INF/l10n/bundle. The Bundle-Localization manifest header can be used to override the default base name for the localization files. This location is relative to the root of the bundle and bundle fragments.
A localization entry contains key/value entries for localized information. All headers in a bundle's manifest can be localized. However, the Framework must always use the non-localized versions of headers that have Framework semantics.
A localization key can be specified as the value of a bundle's manifest header using the following syntax:
本地值被保存在bundle中的属性资源中。bundle本地化属性文件的默认基础名是OSGI-INF/l10n/bundle。头Bundle-Localization用于重载这个默认值,路径是相对于bundle和片段bundle的根路径。
一个本地化实体包含用于本地信息的key/value实体。manifest中所有的头都能被本地化。然而,框架必须始终使用含有框架语义的头的非本地化版本。
使用以下语法指定manifest头中的本地化值
header-value ::= ’%’text
text ::= < any value which is both a valid manifest header value and a valid property key name >
For example, consider the following bundle manifest entries:
Bundle-Name: %acme bundle
Bundle-Vendor: %acme corporation
Bundle-Description: %acme description
Bundle-Activator: com.acme.bundle.Activator
Acme-Defined-Header: %acme special header
User-defined headers can also be localized. Spaces in the localization keys are explicitly allowed.
用户定义的头也能被本地化。本地化KEY是可以包含空格的
The previous example manifest entries could be localized by the following entries in the manifest localization 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
The above manifest entries could also have French localizations in the manifest localization entry OSGI-INF/l10n/bundle_fr_FR.properties.
3.11 Bundle Validity
If the Bundle-ManifestVersion is not specified, then the bundle manifest version defaults to 1, and certain Release 4 syntax, such as a new manifest header, is ignored rather than causing an error. Release 3 bundles must be treated according to the R3 specification.
如果Bundle-ManifestVersion没有被指定,那么将被设置成默认值1,对于版本4的语法,像这种新manifest头,将被忽略,而不是抛出错误。版本3的bundle必须根据版本3规范使用。
The following (non-exhaustive) list of errors causes a bundle to fail to install:
下面的错误列表会使bundle安装失败:
• Bundle-RequireExecutionEnvironment header does not match the available execution environments.
• 头Bundle-RequireExecutionEnvironment不匹配可用的执行环境
• Missing Bundle-SymbolicName.
• 缺少头Bundle-SymbolicName
• Duplicate attribute or duplicate directive (except in the Bundle-Native code clause).
• 多个属性或指令
• Multiple imports of a given package.
• 对一个包的多次引入
• Export or import of java.*.
• 输出或引入java.*
• Export-Package with a mandatory attribute that is not defined.
• Export-Package的强制属性是没有定义的(3.6.6关于强制属性的定义)
• Installing a bundle that has the same symbolic name and version as an already installed bundle.
• 安装一个bundle,与已经安装的bundle具有相同的标记名和版本
• Updating a bundle to a bundle that has the same symbolic name and version as another installed bundle.
• 更新一个bundle,与已经安装的bundle具有相同的标记名和版本
• Any syntactic error (for example, improperly formatted version or bundle symbolic name, unrecognized directive value, etc.).
• 任何语法错误(例如,不正确的版本和标记名格式,无效的的指令等)
• Specification-version and version specified together (for the same package(s)) but with different values on manifest headers that treat them as synonyms. For example:
• 为同一个包同时指定Specification-version和version相同的值。
Import-Package p;specification-version=1;version=2
would fail to install, but:
Import-Package p;specification-version=1, q;version=2
would not be an error.
• The manifest lists a OSGI-INF/permission.perm file but no such file is present.
• manifest指定了OSGI-INF/permission.perm文件,却没有这个文件存在。
• Bundle-ManifestVersion value not equal to 2, unless the Framework specifically recognizes the semantics of a later release.
• Bundle-ManifestVersion的值不等于2,除非框架明确给出后面的版本的语义
3.12 Optional
This specification provides for one optional mechanism: the boot class path extension. The reason to make this mechanism optional is that it is not possible to implement this in a portable way. A compliant framework must set the following property to true or false depending on the implementation of the boot class path extension:
• org.osgi.supports.bootclasspath.extension
If the property is not set or the value is unrecognized, then the value defaults to false. A Framework that does not implement the bootclasspath extension must refuse to install or update a bundle that carries this option. It must then throw an exception at install or update time.
Additionally, frameworks must implement fragments, require bundle, and extensions. They must therefore set the following properties to true.
这部分规范提供了一个可选机制:boot类路径扩展。将这个机制做成可选的原因是它不可能很轻易被实现。一个适应性强的框架必须根据对boot类路径扩展的实现来设置这个属性的值为true或false。
• org.osgi.supports.bootclasspath.extension
如果这个属性没有设置,或没有赋值,那么默认值为false。一个没有实现bootclasspath extension的框架必须拒绝安装或更新一个带有这个选项的bundle。然后抛出一个exception。
另外,框架必须实现fragments, require bundle, and extensions。因此一下属性必须赋值为true:
• org.osgi.supports.framework.requirebundle
• org.osgi.supports.framework.fragments
• org.osgi.supports.framework.extension
3.13 Requiring Bundles
The Framework supports a mechanism where bundles can be directly wired to other bundles. The following sections define the relevant headers and then discuss the possible scenarios. At the end, some of the (sometimes unexpected) consequences of using Require-Bundle are discussed.
框架支持bundle直接连接到另外的bundle机制。一下章节定义了相关的头,然后讨论可能的假设。最后,讨论一些使用Require-Bundle的结果。
3.13.1 Require-Bundle
The Require-Bundle manifest header contains a list of bundle symbolic names that need to be searched after the imports are searched but before the bundle’s class path is searched. Fragment or extension bundles can not be required. Only packages that are marked exported by the required bundles are visible to the requiring bundle.
The Require-Bundle manifest header must conform to the following syntax:
头Require-Bundle包含了bundle标记名的列表,这些标记名需要在引入查找之后,bundle类路径查找之前被查找。片段或扩展不是必须的。只有被 required bundles标记为输出的包材对requiring bundle可见。
Require-Bundle ::= bundle-description( ',' bundle-description )*
bundle-description ::= symbolic-name // See 1.3.2(';' parameter )*
The following directives can be used in the Require-Bundle header:
以下指令可以用在头Require-Bundle中:
• visibility – If the value is private (Default), then all visible packages from the required bundles are not re-exported. If the value is reexport then bundles that require this bundle will transitively have access to these required bundle’s exported packages. That is, if bundle A requires bundle B, and bundle B requires bundle C with visibility:=reexport then bundle A will have access to all bundle C’s exported packages as if bundle A had required bundle C.
• visibility – 如果值是private(默认值),那么所有required bundles中可见的包都不会重新输出。如果值是reexport ,那么需要这个bundle的bundles将可以访问这些required bundle输出的包。也就是说,如果bundle A需要bundle B,bundle B需要bundle C,bundle B的头Require-Bundle 的visibility ="reexport",那么A将可以访问C输出的包,就像A需要C一样。
• resolution – If the value is mandatory (default) then the required bundle must exist for this bundle to resolve. If the value is optional, the bundle will resolve even if the required bundle does not exist.
• resolution – 如果值是mandatory (默认值),那么required bundle必须存在用于解析这个bundle。如果值是optional,那么这个bundle将会被解析,即使required bundle不存在。
The following matching attribute is architected by the Framework:
以下匹配属性由框架构造:
• bundle-version – The value of this attribute is a version range to select the bundle version of the required bundle. See Version Ranges on page 28. The default value is [0.0.0,∞).
• bundle-version – 这个属性的值是一个版本范围,用于选择required bundle的版本。默认值是[0.0.0,∞)。
A given package may be available from more than one of the required bundles. Such packages are named split packages because they derive their contents from different bundles. If these different bundles provide the same classes unpredictable shadowing of classes can arise, see Issues With Requiring Bundles on page 66. However, split packages without shadowing are explicitly permitted.
For example, take the following setup:
A: Require-Bundle: B
Export-Package: p
B: Export-Package: p;partial=true;mandatory:=partial
If bundle C imports package p, it will be wired to package A.p, however the contents will come from B.p > A.p. The mandatory attribute on bundle B’s export definition ensures that bundle B is not accidentally selected as exporter for package p. Split packages have a number drawbacks that are discussed in Issues With Requiring Bundles on page 66.
如果bundle C引入包p,它将被连接到包A.p,可是这个包是从B.p到A.p。bundle B的输出定义的强制属性确保了bundle B不会被意外的选择为包p的输出者。
Resources and classes from a split package must be searched in the order in which the required bundles are specified in the Require-Bundle header.
As an example, assume that a bundle consists of a number of bundles and a number of language resources (also bundles) that are optional.
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
A bundle may both import packages (via Import-Package) and require one or more bundles (via Require-Bundle), but if a package is imported via Import-Package, it is not also visible via Require-Bundle: Import-Package takes priority over Require-Bundle, and packages which are exported by a required bundle and imported via Import-Package must not be treated as split packages.
In order to be allowed to require a named bundle, the requiring bundle must have BundlePermission[<bundle symbolic name>, REQUIRE], where the bundle symbolic name is the name of the bundle that is required. The required bundle must be able to provide the bundle and must therefore have BundlePermission[<bundle symbolic name>, PROVIDE], where the name designates the requiring bundle. In the case a Fragment bundle requires another bundle, the Bundle Permission must be checked against the Fragment bundle’s Protection Domain.
一个bundle可以同时引入包(通过Import-Package)和require一个或多个bundles(通过Require-Bundle),但是如果一个包通过Import-Package被引入,那么通过Require-Bundle引入的相同的包不会可见,因为Import-Package的优先级大于Require-Bundle,被required bundle输出并通过Import-Package引入的包不能当作split包来对待。
为了被允许需求一个命名bundle,requiring bundle必须有BundlePermission[<bundle symbolic name>, REQUIRE](bundle权限),这里的bundle symbolic name是被需要的bundle的名字。这个被需要的bundle必须能提供自己出去,因此它必须有BundlePermission[<bundle symbolic name>, PROVIDE],这里的bundle symbolic name指向那个requiring bundle。在片段bundle需求其他bundle的情况下,bundle权限必须与片段bundle的域保护进行核查(这里应该是指宿主bundle的权限)。
3.13.2 Split Package Compatibility
A package is a split package whenever there are multiple sources for the package; only bundles using the Require-Bundle header can have split packages.
A source is a bundle that provides the given package. Both the required bundles as well as the requiring bundle can act as a source. The required bundles and the requiring bundle can only contribute their exported packages.
Exported split packages from two bundles are compatible if the package sources for one are a subset of the other.
对于一个包来说,只要有多个源,那它就是一个分隔包;只有使用头Require-Bundle的bundle才有分隔包。
一个源是提供了这个包的bundle。required bundles和requiring bundle都可以成为一个源,它们只能分发它们自己的输出包。
从两个bundle输出的分隔包是兼容的,如果这个包的其中一个源是另一个源的子集。
3.13.3 Issues With Requiring Bundles
The preferred way of wiring bundles is to use the Import-Package and Export-Package headers because they couple the importer and exporter to a much lesser extent. Bundles can be refactored to have a different package composition without causing other bundles to fail.
The Require-Bundle header provides a way for a bundle to bind to all the exports of another bundle, regardless of what those exports are. Though this can seem convenient at first, it has a number of drawbacks:
连接bundles的首选方式是使用头Import-Package和Export-Package,因为它们将输出者和引入者连接到一个很小的范围,bundles可以被重构来含有一个不同的组成包,而不需要使其他bundles失败。
头Require-Bundle提供的方式是绑定那个bundle所有的输出包,而不管这些输出包是什么。尽管这看起来很方便,但是有以下缺点:
• Split Packages – Classes from the same package can come from different bundles with Require bundle, such a package is called a split package. Split packages have the following drawbacks:
• Split Packages – 同一个包中的类,可以来自不同的bundles,这个包成为分隔包。分隔包有以下缺点:
• Completeness – Split packages are open ended, there is no way to guarantee that all the intended pieces of a split package have actually been included.
• Completeness – 分隔包是入口处,没有办法保证所有这个分隔包所需的部分都已经被包含了。
• Ordering – If the same classes are present in more than one required bundle, then the ordering of Require-Bundle is significant. A wrong ordering can cause hard to trace errors, similar to the traditional class path model of Java.
• Ordering – 如果相同的类出现在多个required bundle中,那么Require-Bundle的顺序就变得很重要了,一个错误的顺序会让错误跟踪变得很难,这与JAVA传统的类路径模式相似。
• Performance – A class must be searched in all providers when packages are split. This increases the number of times that a ClassNotFoundException must be thrown which can introduce a significant overhead.
• Performance –在分隔包中,一个类必须被查找于所有的提供者,这会增加ClassNotFoundException必须被抛出的次数,这是很大的性能支出。
• Confusing – It is easy to find a setup where there is lots of potential for confusion. For example, the following setup is non-intuitive.
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
In this example, bundle D merges the split package q from bundles B and bundle C, however, importing package p from bundle A puts a uses constraint on package p for package q. This implies that bundle D can see the valid package q from bundle B but also the invalid package q from bundle C. This wiring is allowed because in almost all cases there will be no problem. However, the consistency can be violated in the rare case when package C.q contains classes that are also in package B.q.
在这个例子中,bundle D合并了bundle B和C的包q,可是A.p,为包q设置了uses指令,约束到包A.p上。这暗示了bundle D可以看见可用的B.q,也可以看见不可用的C.q(头
Require-Bundle中,B在C前面)。这个连接是被允许的,在大多数案例中不会有问题。但是,当C.q和B.q中包含同相同的类时,就会发生问题。
• Mutable Exports – The feature of visibility:=reexport that the export signature of the requiring bundle can unexpectedly change depending on the export signature of the required bundle.
• Mutable Exports – visibility:=reexport的特性,requiring bundle的输出信号可以根据required bundle的输出信号而发生不可预期的改变。
• Shadowing – The classes in the requiring bundle that are shadowed by those in a required bundle depend on the export signature of the required bundle and the classes the required bundle contains. (By contrast, Import-Package, except with resolution:=optional, shadows whole packages regardless of the exporter.)
• Shadowing – the requiring bundle中的类会被那些required bundle遮挡,根据required bundle的输出信号和包含的类(相比之下,Import-Package,除了resolution:=optional,会遮挡所有的包而不管输出者)。(深层优先的类路径查找顺序)
• Unexpected Signature Changes – The Require-Bundle directive visibility:=private (the default) may be unexpectedly overridden in some circumstances as the following example shows.
• Unexpected Signature Changes – 在某些情况下,Require-Bundle的指令visibility:=private可能会出乎预料的被重载
A: p (private, not exposed in manifest)
Require-Bundle: B;visibility:=reexport,
C;visibility:=private
B: Export-Package: p
C: Export-Package: p
The export signature of bundle A will consist of only package p. However, package p is split. The Framework searches for a class in package p in bundle B, then bundle C, and last bundle A.
So the visibility:=private directive on Require-Bundle C had no effect relative to package p. However, if bundle B was changed to stop exporting package p, then the directive would take effect and package p would drop out of bundle A's export signature. This is depicted in Figure 3.22.
bundle A的输出信号仅由包p组成,可是包p是个分隔包。框架会先在bundle B中的包p中查找一个类,然后再在bundle C中查找,最后才查找bundle A。所以Require-Bundle C上的指令visibility:=private不会影响到包p。但是,如果bundle B停止输出包p,那么这个指令将会受到影响,包p也将退出bundle A的输出信号。
3.14 Fragment Bundles
Fragments are bundles that are attached to a host bundle by the Framework. Attaching is done as part of resolving: the Framework appends the relevant definitions of the fragment bundles to the host’s definitions before the host is resolved. Fragments are therefore treated as part of the host, including any permitted headers; they must not have their own class loader. Fragments must have their own Protection Domain.
A key use case for fragments is providing translation files for different locales. This allows the translation files to be treated and shipped independently from the main application bundle.
When an attached fragment bundle is updated, the content of the previous fragment must remain attached to its host bundle. The new content of the updated fragment must not be allowed to attach to the host bundle until the Framework is restarted or the host bundle is refreshed. During this time, an attached fragment will have two versions: the old version, attached to the
old version of the host, and a new fragment bundle that can get attached to a new version or to a different host bundle.
片段是由框架附加在一个主bundle上的bundles。附加过程是解析过程的一部分:框架在主bundle被解析之前将片段bundles的相关定义附加到主bundle的定义上。因此,片段可看作主bundle的一部分,包括所有允许的头。片段必须不能有它们自己的class loader。片段必须有它们自己的保护域。
片段的一个重要案例是为不同的locales提供翻译文件。这允许翻译文件可独立于主应用bundle被处理和装载。
当一个片段被更新时,上一个片段的内容必须被保留在它的宿主bundle上。更新片段的内容必须不能被附加到那个宿主bundle,知道框架重启或那个宿主bundle被刷新。期间,这个片段会有2个版本:老版本,附加在老版本的宿主bundle,新的片段能附加在一个新版本的bundle或是其他宿主bundle上。
In this case, the Package Admin service must return information only for the last version of the supplied bundles. In the previous described case, the getHosts method must return the host bundle of the new version of the fragment bundle, and the getFragments method must return the fragment bundles attached to the new version of the host bundle.
在这里,Package Admin service必须只能为那个提供的bundle最后面的那个版本返回信息。在前面的例子中,getHosts方法必须返回新版本片段bundle的宿主bundle,getFragments方法必须返回附加在新的主bundle上的片段bundle。
When attaching a fragment bundle to a host bundle the Framework must perform the following steps:
当附加一个片段bundle到一个主bundle时,框架必须执行以下步骤:
1 Append the import definitions for the Fragment bundle that do not conflict with an import definition of the host to the import definitions of the host bundle. A Fragment can provide an import statement for a private package of the host. The private package in the host is hidden in that case.
2 Append the Require-Bundle entries of the fragment bundle that do not conflict with a Require-Bundle entry of the host to the Require-Bundle entries of the host bundle.
3 Append the export definitions of a Fragment bundle to the export definitions of the host bundle unless the exact definition (directives and attributes must match) is already present in the host. Fragment bundles can therefore add additional exports for the same package name. The bundle-version attributes and bundle-symbolic-name attributes will reflect the host bundle.
1. 将片段bundle中不影响主bundle引入定义的引入定义添加到主bundle的引入定义中。一个片段可以为主bundle中一个私有包提供引入声明,主bundle中的那个私有包是隐藏的。
2. 将片段bundle中不影响主bundle的Require-Bundle实体的Require-Bundle实体添加到zhu主bundle的Require-Bundle实体中。
3. 将片段bundle中不影响主bundle输出定义的输出定义添加到主bundle的输出定义中,除非主bundle中已经有了这样一个定义(指令和属性必须匹配)。因此,片段bundles可以有对同一个包名的输出。属性bundle-version和属性bundle-symbolic-name将会反射到主bundle。
A host and a fragment conflict when they cannot resolve to provide a consistent class space. If a conflict is found, the Fragment bundle is not attached to the host bundle.
A Fragment bundle must enter the resolved state only if it has been successfully attached to its host bundle. During runtime, the fragment’s JAR is searched after the host’s bundle class path as described in Fragments During Runtime on page 70.
A Fragment bundle can not be required by another bundle with the Require-Bundle header.
当一个主bundle和一个片段bundle不能解析来提供一个一致的的类空间时,它们会发生冲突,片段bundle将不再添加到这个主bundle。
一个片段bundle仅当它成功附加到一个主bundle后,它才进入resolved状态,它的JAR包将在主bundle的类路径之后被查找。
其他bundle不能使用头Require-Bundle来require一个片段bundle。
3.14.1 Fragment-Host
A fragment is a bundle that is attached to one other bundle called its host bundle. The components of the fragment, like the Bundle-Classpath and other definitions, are added at the end of the related definitions of the host bundle. In the case of the Export-Package header, bundle dependent attributes like bundle-version and bundle-symbolic-name come from the host. All classes and resources within the fragment bundle must be loaded using the class loader of the host bundle.
一个片段是一个bundle,被它附加的另一个bundle叫做它的宿主bundle。片段bundle的组件,就像Bundle-Classpath或其他定义,被添加在主bundle的相关定义的末尾。在头Export-Package中,bundle依赖的属性,例如bundle-version和bundle-symbolic-name均来自主bundle。片段bundle中所有的类和资源必须使用主bundle的class loader加载。
The Fragment-Host manifest header must conform to the following syntax:
Fragment-Host ::= bundle-description
bundle-description ::= symbolic-name
(';' parameter ) * // See 1.3.2
The following directives are architected by the Framework for Fragment-Host:
框架为Fragment-Host构造了以下指令:
• extension – Indicates this extension is a system or boot class path extension. It is only applicable when the Fragment-Host is the System Bundle. This is discussed in Extension Bundles on page 72. The following values are supported:
• extension – 指这个扩展是系统或boot 类路径扩展,它只能在Fragment-Host(宿主bundle)是系统bundle的情况下才可用。支持以下值:
• framework - The fragment bundle is a Framework extension bundle.
• framework - 片段bundle是框架的扩展bundle。
• bootclasspath - The fragment bundle is a boot class path extension bundle.
• bootclasspath - 片段bundle是boot类路径扩展bundle。
The fragment must be the bundle symbolic name of the implementation specific system bundle or the alias system.bundle. The Framework should fail to install an extension bundle when the bundle symbolic name is not referring to the system bundle.
片段必须是实现特殊系统bundle的bundle标记名或别名system.bundle(应该是指片段bundle的标记名)。当片段的标记名没有引用到系统bundle时,框架必须使这个扩展安装失败。
The following attributes are architected by the Framework for Fragment-Host:
• bundle-version – The version range to select the bundle that provides the host bundle. See Version Matching on page 41. The default value is [0.0.0,∞).
• bundle-version – 版本范围,用于选择提供宿主的bundle
When a fragment bundle becomes resolved, the Framework must attach the
fragment bundle to the selected host bundle with the highest version.
When a fragment bundle is attached to its host bundle, it logically becomes part of it. All classes and resources within the fragment bundle must be loaded using the class loader of its host bundle. The fragment bundles of a host bundle must be attached to the host bundle in the order that the fragment bundles are installed, which is in ascending bundle ID order. If an error occurs during the attachment of a fragment bundle then the fragment bundle must not be attached to the host. A fragment bundle must enter the resolved state only if it has been successfully attached to its host bundles.
In order for a host bundle to allow fragments to attach, the host bundle must have BundlePermission[<bundle symbolic name>,HOST]. In order to be allowed to attach to a host bundle, a fragment bundle must have BundlePermission[<bundle symbolic name>,FRAGMENT].
当一个片段bundle解析之后,框架必须将这个片段bundle附加到被选择的版本最高的主bundle上。
当一个片段bundle被附加到它的主bundle后,理论上它就成了主bundle的一部分。片段bundle中所有的类和资源必须使用它的宿主bundle的class loader去加载。一个主bundle的片段bundles必须按照它们被安装的顺序附加到主bundle上,也就是根据他们的bundle ID的升序。如果在附加过程中发生错误,那么片段bundle不能附加到主bundle上。一个片段bundle只有在成功附加到它的所有主bundles后才能进入resolved状态。
为了使一个主bundle允许被附加片段,这个主bundle必须有BundlePermission[<bundle symbolic name>,HOST],为了使一个片段被允许附加到一个主bundle,这个片段bundle必须有a fragment bundle must have BundlePermission[<bundle symbolic name>,FRAGMENT]
3.14.2 Fragments During Runtime
All class or resource loading of a fragment is handled through the host’s class loader, a fragment must never have its own class loader. Fragment bundles are treated as if they are an intrinsic part of their host.
Though a fragment bundle does not have its own class loader, it still must have a separate Protection Domain when it is not an extension fragment. Each fragment can have its own permissions linked to the fragment bundle’s location and signer.
A host bundle’s class path is searched before a fragment’s class path. This implies that packages can be split over the host and any of its fragments. Searching the fragments must be done in ascending bundle ID order. This is the order that the fragment bundles were installed.
片段所有类和资源的加载都由它的主bundle的class loader来处理,它不能拥有自己的class loader。片段bundles被看成是它们的宿主bundle的一部分。
尽管一个片段bundle没有它自己的class loader,如果它不是一个扩展片段,它还是必须有一个保护域。每个片段都有它自己的连接到片段bundle的路径和签名者的权限。
一个主bundle的类路径在片段bundle的类路径之前被查找,这暗示了包可以被分割到主bundle和片段bundles。片段的查找必须根据它们被安装后的ID的升序进行。
Figure 3.23 shows a setup with two fragments. Bundle B is installed before bundle C and both bundle B and bundle C attach to bundle A. The following table shows where different packages originate in this setup. Note that the order of the append (>) is significant.
图3.23显示了两个片段的设置。bundle B在C之前被安装,它们都被附加到bundle A。下面的表格显示了这个安装的两个包的本质区别,注意>的顺序是很重要的。
Table 3.4 Effect of fragments on searching
Package Requested |
From |
Remark |
p |
A.p > B.p |
Bundle A exports package p, therefore, it will search its class path for p. This class path consists of the JAR and then its Fragment bundles. |
q |
D.q |
The import does not handle split packages and package q is imported from bundle D. Therefore, C.q is not found. |
r |
A.r > B.r |
Package r is not imported and therefore comes from the class path. |
s |
C.s |
|
t |
B.t > C.t |
|
In the example above, if package p had been imported from bundle D, the table would have looked quite different. Package p would have come from bundle D, and bundle A’s own contents as well as the contents of bundle B would have been ignored.
在上面的例子中,如果包p是从bundle D引入的,那么这个表格将发生很大变化。包p来自bundle D,A.p和B.p将被忽略(D的类路径先被查找)。
If package q had bundle D, then the class path would have to be searched, and A.q would have consisted of A.q > C.q.
Fragments must remain attached as long as the host remains resolved. When a host bundle becomes unresolved, then all attached Fragment bundles must be detached from the host bundle. When a fragment bundle becomes unresolved the Framework must:
• Detach it from the host
• Re-resolve the host bundle
• Reattach the remaining attached fragment bundles.
A Fragment bundle can become unresolved by calling the refreshPackages method or the resolveBundle method on itself or on its host.
主bundle处于resolved期间,片段bundle必须一直保持附加状态。当一个主bundle变成unresolved时,所有的附加片段bundle必须从主bundle分离出来。当一个片段bundle变得unresolved时,框架必须:
• 将其分离出主bundle
• 重新解析主bundle
• 重新附加片段bundles
一个片段bundle可以通过调用方法refreshPackages或调用主bundle的或它自己的resolveBundle方法变成unresolved。
3.14.3 Illegal Manifest Header for Fragment Bundles
The following list contains the headers that must not be used in a fragment bundle:
一下列表包含了在一个片段bundle中必须不能使用的头:
• Bundle-Activator
3.15 Extension Bundles
Extension bundles can deliver optional parts of the Framework implementation or provide functionality that must reside on the boot class path. These packages cannot be provided by the normal import/export mechanisms.
扩展bundles能够提供框架实现的可选部分或提供必须在boot类路径中的功能(包)。这些包不能使用平常的引入/输出机制。
Boot class path extensions are necessary because certain package implementations assume that they are on the boot class path or are required to be available to all clients. An example of a boot class path extension is an implementation of java.sql such as JSR 169. Boot class path extensions are not required to be implemented by a compliant framework, see Optional on page 64.
Boot类路径扩展是有必要的,因为某些实现包假设它们处于boot类路径上或对所有required的客户端可用。boot类路径扩展的一个例子是java.sql的实现,就像JSR 169.boot类路径扩展的实现不是必须的。
Framework extensions are necessary to provide implementation aspects of the Framework. For example, a Framework vendor could supply the optional services like Permission Admin service and Start Level service with Framework extension bundles.
框架扩展对于提供框架的实现部分是由必要的。例如,一个框架提供者可以通过扩展bundles提供一些可选服务,就像Permission Admin service和 Start Level service
An extension bundle should use the bundle symbolic name of the implementation system bundle, or it can use the alias of the system bundle, which is system.bundle.
一个扩展bundle应该使用系统实现bundle的标记名,或使用系统bundle的别名system.bundle。
The following example uses the Fragment-Host manifest header to specify an extension bundle for a specific Framework implementation.
下面这个例子使用头Fragment-Host来指定一个框架细节实现的扩展bundle。
Fragment-Host: com.acme.impl.framework; extension:=framework
The following example uses the Fragment-Host manifest header to specify a boot class path extension bundle.
Fragment-Host: system.bundle; extension:=bootclasspath
The following steps describe the life cycle of an extension bundle:
下面的步骤描述了一个扩展bundle的生命周期:
1 When an extension bundle is installed it enters the INSTALLED state.
2 The extension bundle is allowed to enter the RESOLVED state at the Frameworks discretion, which can require a Framework re-launch.
3 If the extension bundle is refreshed then the Framework must shutdown, the host VM must terminate, and the Framework must be relaunched.
4 If a RESOLVED extension bundle is refreshed then the Framework must shutdown; the host VM must terminate and framework must be relaunched.
5 When a RESOLVED extension bundle is updated or UNINSTALLED, it is not allowed to re-enter the RESOLVED state. If the extension bundle is refreshed then the Framework must shutdown; the host VM must terminate and framework must be re-launched.
1. 当一个扩展bundle被安装后,它进入INSTALLED状态。
2. 扩展bundle可以进入RESOLVED状态,这由框架自行决定,但是需要框架重启。
3. 如果这个扩展bundle被刷新,那么框架必须shutdown,VM必须终止,框架必须被重启。
4. 如果一个resolved状态的扩展bundle被刷新,那么框架必须shutdown,VM必须终止,框架必须被重启。
5. 当一个resolved状态的扩展bundle被更新或进入uninstalled状态时,它将不允许重新进入resolved状态,如果它被刷新,那么框架必须shutdown,VM必须终止,框架必须被重启。
It is valid to update an extension bundle to a bundle of another type. If the old extension bundle is resolved then it must be attached as a fragment to the system bundle. When this bundle is updated the old content of the bundle must remain attached to the system bundle until the system bundle is refreshed or the extension bundle is refreshed (using Package Admin service). This must initiate a VM and Framework restart. When the framework comes back up the new content of the bundle may be resolved.
All Bundle events should be dispatched for extension bundles as for ordinary bundles.
可以将扩展bundle更新成其他类型的bundle。如果原来的那个扩展bundle处于resolved状态,那么它必须被作为一个片段附加到系统bundle。当这个bundle被更新后,它以前的内容必须保持附加在系统bundle知道系统bundle被刷新或这个扩展bundle被刷新。这必须使一个VM和框架重启。当框架重启后,新bundle可以被解析。
所有的bundle事件必须被分发到扩展bundle,与普通bundle一样。
3.15.1 Illegal Manifest Headers for Extension Bundles
An extension bundle must throw a BundleException if it is installed or updated and it specifies any of the following headers.
如果一个扩展bundle被安装或更新并且指定了下列任何一个头,必须抛出一个BundleException
• Import-Package
• Require-Bundle
• Bundle-NativeCode
• DynamicImport-Package
• Bundle-Activator
Both boot class path and framework extension bundles are permitted to specify an Export-Package header. Any exported packages specified by a framework extension bundle must be exported by the System Bundle when the extension bundle is resolved.
boot类路径和框架扩展bundle都可以指定头Export-Package。当扩展bundle被解析时,所有它指定的输出包都必须由系统bundle来输出。
3.15.2 Class Path Treatment
A boot class path extension bundle’s JAR file must be appended to the boot class path of the host VM. A framework extension bundle’s JAR is appended to the class path of the Framework.
Extension bundles must be appended to their class path in the order in which the extension bundles are installed: that is, ascending bundle ID order.
How a framework configures itself or the boot class path to append the extension bundle’s JAR is implementation specific. In some execution environments, it may be impossible to support extension bundles. In such environments, the Framework must throw a BundleException when such an
extension bundle is installed. The resulting Bundle Exception must have a cause of type UnsupportedOperationException.
一个boot类路径扩展bundle的JAR包文件必须添加到VM的boot类路径中,一个框架扩展bundle的JAR包文件必须被添加到框架的类路径中。
扩展bundle必须根据他们被安装时ID的升序被添加到它们的类路径中。
一个框架配置或boot类路径如何添加扩展bundle的JAR包文件是一个特殊实现。在一个执行环境中,可能不支持扩展bundle。如果是这样,扩展bundle被安装时,框架必须抛出一个BundleException ,包含 cause of UnsupportedOperationException
3.16 Security
3.16.1 Extension Bundles
In an environment that has Java 2 security enabled the Framework must perform an additional security check before allowing an extension bundle to be installed. In order for an extension bundle to successfully install, the Framework must check that the extension bundle has All Permissions assigned to it. This means that the permissions of an extension bundle must be setup before the extension bundle is installed.
在JAVA2安全环境中,框架必须在允许扩展bundle被安装之前执行一个额外的安全检查。为了成功安装一个扩展bundle,框架必须检查扩展bundle的权限。也就是说在扩展bundle被安装之前,它的权限必须被设置。
AllPermission must be granted to extension bundles because they will be loaded under the Protection Domain of either the boot class path or the Framework implementation. Both of these Protection Domains have All Permissions granted to them. It must therefore not be allowed for an extension bundle to be installed unless it already has been granted AllPermissions.
扩展bundle必须被授予所有权限,因为他们将被加载于它们的boot类路径或框架实现的保护域中。这些保护域都被授予了所有权限。因此除非一个扩展bundle有所有权限,否则不能被安装。
The installer of an extension bundle must have AdminPermission[<extension bundle>,EXTENSIONLIFECYCLE] to install an extension bundle.
扩展bundle的安装者必须有AdminPermission[<extension bundle>,EXTENSIONLIFECYCLE]权限。
3.16.2 Bundle Permission
Most package sharing permissions are based on Package Permission. However, fragments and required bundles use the bundle symbolic name to handle sharing. The Bundle Permission is used to control this type of package sharing.
大部分包共享权限是基于Package Permission的。可是片段bundle和required bundles是使用bundle标记名来操作共享的。Bundle Permission就是用来控制这种类型的包共享。
The name parameter of the Bundle Permission is a bundle symbolic name. The symbolic name is used as the identifier for the target bundle. A wild card (’.*’ \u002E,\u002A) is permitted at the end of the name.
Bundle Permission的参数name是一个bundle的标记名,这个标记名用作目标bundle的标识符,通配符"*"可以跟在名字的结尾。
For example, if fragment bundle A attaches to its host bundle B then fragment bundle A requires BundlePermission("B", "fragment") so that A is permitted to target host bundle B. The direction of the actions is depicted in Figure 3.24.
The following actions are architected:
• provide – Permission to provide packages to the target bundle.
• require – Permission to require packages from the target bundle.
• host – Permission to attach to the target fragment bundle.
• fragment – Permission to attach as a fragment to the target host bundle.
When a fragment contains a Require-Bundle header, the Framework must check the permission against the domain of the fragment.
3.16.3 Package Permission
Bundles can only import and export packages for which they have the required permission. A PackagePermission must be valid across all versions of a package.
A PackagePermission has two parameters:
• The package that may be exported or imported. A wildcard may be used. The granularity of the permission is the package, not the class name.
• The action, either IMPORT or EXPORT. If a bundle has permission to export a package, the Framework must automatically grant it permission to import the package.
A PackagePermission with * and EXPORT as parameters allows the import and export of any package.
When a fragment adds imports and exports to the host, the framework must check the protection domain of the fragment and not of the related host.
3.16.4 Resource Permissions
A Framework must always give a bundle the RESOURCE, METADATA, and CLASS AdminPermission actions to access the resources contained within:
• Itself
• Any attached fragments
• Any resources from imported packages
A resource in a bundle may also be accessed by using certain methods on Bundle. The caller of these methods must have AdminPermission[bundle, RESOURCE].
If the caller does not have the necessary permission, a resource is not accessible and null must be returned. Otherwise, a URL object to the resource must be returned. These URLs are called bundle resource URLs. Once the URL object is returned, no further permission checks are performed when the contents of the resource are accessed. The URL object must use a scheme
defined by the Framework implementation.
Bundle resource URLs are normally created by the Framework, however, in certain cases bundles need to manipulate the URL to find related resources. For example, a URL can be constructed to a resource that is in the same directory as a given resource.
URLs that are not constructed by the Framework must follow slightly different security rules due to the design of the java.net.URL class. Not all constructors of the URL class interact with the URL Stream Handler classes (the implementation specific part). Other constructors call at least the parseURL method in the URL Stream Handler where the security check can take place.
This design makes it impossible for the Framework check the permissions during construction of a bundle resource URL.
The following constructors use the parseURL method and are therefore checked when a bundle resource URL is constructed.
URL(String spec)
URL(URL context, String spec)
URL(URL context, String spec, URLStreamHandler handler)
When one of these constructors is called for a bundle resource URL, the implementation of the Framework must check the caller for the necessary permissions in the parseURL method. If the caller does not have the necessary permissions then the parseURL method must throw a Security Exception. This will cause a Malformed URL Exception to be thrown by the URL constructor. If the caller has the necessary permissions, then the URL object is setup to access the bundle resource without further checks.
The following java.net.URL constructors do not call the parseURL method in the URL Stream Handler, making it impossible for the Framework to verify the permission during construction.
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 URLs that are created with these constructors cannot perform the permission check during creation and must therefore delay the permission check. When the content of the URL is accessed, the Framework must throw a Security Exception if the caller does not have
AdminPermission[bundle, RESOURCE] for the bundle referenced by the URL.
3.16.5 Permission Checks
Since multiple bundles can export permission classes with the same class name, the Framework must make sure that permission checks are performed using the correct class. For example, a bundle that calls the check-Permission method provides an instance of the Permission class:
void foo(String name) {
checkPermission(new FooPermission(name,"foo"));
}
This class of this Permission instance comes from a particular source. Permissions can only be tested against instances that come from the same source.
Therefore, the Framework needs to look up permissions based on class rather than class name. When it needs to instantiate a permission it must use the class of the permission being checked to do the instantiation. This is a complication for Framework implementers; bundle programmers are not affected.
Consider the following example:
Bundle A
Import-Package: p
Export-Package: q
Bundle B
Import-Package: p
• Bundle A uses a p.FooService. Usage of this class checks q.FooPermission whenever one of its methods is invoked.
• Bundle B has a FooPermission in its Protection Domain in a (Conditional) Permission Info object.
• Bundle B invokes a method in the FooService that was given by bundle A.
• The FooService calls the checkPermission method with a new FooPermission instance.
• The Framework must use a FooPermission object that is from the same class loader as the given FooPermission object before it can call the implies method. In this case, the FooPermission class comes from package A.q.
After the permission check, bundle B will have a FooPermission instantiated using a class from a package it does not import. It is therefore possible that the Framework has to instantiate multiple variations of the FooPermission class to satisfy the needs of different bundles.
posted on 2008-04-11 10:25
Phrancol Yang 阅读(1620)
评论(1) 编辑 收藏 所属分类:
OSGI