5.1 Introduction
The OSGi Service Layer defines a dynamic collaborative model that is highly integrated with the Life Cycle Layer. The service model is a publish, find and bind model. A service is a normal Java object that is registered under one or more Java interfaces with the service registry. Bundles can register services, search for them, or receive notifications when their registration state changes.
OSGi Service Layer定义了一个与Life Cycle Layer紧密结合的动态协作模型,服务模型是发布,查找和绑定模型。一个服务是一个普通的java对象,在服务注册器中注册于一个或多个java接口之下。bundles可以注册服务(through its BundleContext),查找服务,或当服务的注册状态改变时得到通知。
5.1.1 Essentials
• Collaborative – The service layer must provide a mechanism for bundles to publish, find, and bind to each other’s services without having a priori knowledge of those bundles.
• Collaborative – 服务层必须给bundles提供一个机制用于发布,查找和绑定其他各自bundles的服务,而不需要有这些bundles的先期知识。
• Dynamic – The service mechanism must be able to handle changes in the outside world and underlying structures directly.
• Dynamic – 服务机制必须能直接操作外部的和底层的改变。
• Secure – It must be possible to restrict access to services.
• Secure – 必须能限制服务的访问。
• Reflective – Provide full access to the Service Layer’s internal state.
• Reflective – 提供对服务层内部状态的完全访问。
• Versioning – Provide mechanisms that make it possible to handle the fact that bundles and their services evolve over time.
• Versioning – 提供机制,使其能够操作bundle和它们的服务的变化
• Persistent Identifier – Provide a means for bundles to track services across Framework restarts.
• Persistent Identifier –提供一个方法时bundles能跟踪服务不受框架重启的影响。
5.1.2 Entities
• Service – An object registered with the service registry under one or more interfaces together with properties. This object can be discovered and used by bundles.
• Service – 一个对象,在服务注册器中注册于一个或多个接口的名下,服务可以有属性,这个对象可以被bundles发现并使用。
• Service Registry – Holds the service registrations.
• Service Registry – 服务注册器,保存服务暂住证
• Service Reference – A reference to a service. Provides access to the service’s properties but not the actual service object. The service object must be acquired through a bundle’s Bundle Context.
• Service Reference – 到一个服务的引用。提供了对这个服务的属性的访问,但是并不是真正的服务对象,真正的服务对象必须通过bundle的BundleContext对象获得。
• Service Registration – The receipt provided when a service is registered. The service registration allows the update of the service properties and the unregistration of the service.
• Service Registration – 一个暂住证(意思是收到一个服务的注册,而且就注册在这个证里),服务暂住证允许服务属性的更新和注销服务。
• Service Permission – The permission to use an interface name when registering or using a service.
• Service Permission – 一个权限用于当注册或使用一个服务时使用一个接口名字。
• Service Factory – A facility to let the registering bundle customize the service object for each using bundle.
• Service Factory – 一个灵活的工具,使注册服务的bundle为每一个要使用这个服务的bundle定制服务对象。
• Service Listener – A listener to Service Events.
• Service Event – An event holding information about the registration, modification, or unregistration of a service object.
• Filter – An object that implements a simple but powerful filter language. It can select on properties.
• Invalid Syntax Exception – The exception thrown when a filter expression contains an error.
5.2 Services
In the OSGi Service Platform, bundles are built around a set of cooperating services available from a shared service registry. Such an OSGi service is defined semantically by its service interface and implemented as a service object.
在OSGi服务平台中,bundles从一个共享服务注册器中建造一组可相互协作的服务,这样一个OSGi服务通过它的服务接口来定义的,并被实现为一个服务对象。
The service interface should be specified with as few implementation details as possible. OSGi has specified many service interfaces for common needs and will specify more in the future.
服务接口应该尽可能少的指定实现细节,OSGi已经为通用需求指定了很多服务接口,以后会更多。
The service object is owned by, and runs within, a bundle. This bundle must register the service object with the Framework service registry so that the service’s functionality is available to other bundles under control of the Framework.
服务对象属于一个bundle,并在bundle中运行,bundle必须将这个服务对象注册到框架服务注册器中,以便在框架的控制下,这个服务的功能可以被其他bundles使用。
Dependencies between the bundle owning the service and the bundles using it are managed by the Framework. For example, when a bundle is stopped, all the services registered with the Framework by that bundle must be automatically unregistered.
提供服务的bundle和使用服务的bundle之间的依赖关系由框架来管理。例如,当一个bundle停止后,所有这个bundle注册到框架的服务必须自动注销(由框架来注销)。
The Framework maps services to their underlying service objects, and provides a simple but powerful query mechanism that enables a bundle to request the services it needs. The Framework also provides an event mechanism so that bundles can receive events of services that are registered, modified, or unregistered.
框架将服务映射到它们的服务对象,并提供一个简单而强大的查询机制,使一个bundle请求一个它需要的服务。框架页提供了一个事件机制以便bundles能接收服务注册,修改或注销的事件。
5.2.1 Service References
In general, registered services are referenced through ServiceReference objects. This avoids creating unnecessary dynamic service dependencies between bundles when a bundle needs to know about a service but does not require the service object itself.
通常,注册的服务通过ServiceReference对象去引用它,这就避免了当一个bundle需要知道一个服务但是不需要这个服务对象本身时,创建一个不必要的bundles之间的动态服务依赖关系。
A ServiceReference object can be stored and passed on to other bundles without the implications of dependencies. When a bundle wishes to use the service, it can be obtained by passing the ServiceReference object to BundleContext.getService(ServiceReference). See Locating Services on
page 114.
一个ServiceReference 对象可以被保存并传到别的bundles,而不需要实现依赖关系。当一个bundle想使用这个服务时,它能通过将ServiceReference 对象传到BundleContext.getService(ServiceReference)来获得
A ServiceReference object encapsulates the properties and other metainformation about the service object it represents. This meta-information can be queried by a bundle to assist in the selection of a service that best suits its needs.
When a bundle queries the Framework service registry for services, the Framework must provide the requesting bundle with the ServiceReference objects of the requested services, rather than with the services themselves.
当一个bundle在框架服务注册器中查询服务时,框架必须给这个查询bundle提供它请求的服务的ServiceReference对象,而不是这些服务本身。
A ServiceReference object may also be obtained from a ServiceRegistration object.
一个ServiceReference对象也可以从ServiceRegistration对象那获得。
A ServiceReference object is valid only as long as the service object is registered. However, its properties must remain available as long as the ServiceReference object exists.
ServiceReference对象仅仅只在服务对象被注册时可以使用,但是它的属性会一直可用只要ServiceReferenc对象存在。
5.2.2 Service Interfaces
A service interface is the specification of the service’s public methods. In practice, a bundle developer creates a service object by implementing its service interface and registers the service with the Framework service registry. Once a bundle has registered a service object under an interface name, the associated service can be acquired by bundles under that interface name,
and its methods can be accessed by way of its service interface. The Framework also supports registering service objects under a class name, so references to service interface in this specification can be interpreted to be an interface or class.
一个服务接口是服务的公共方法的规范,在实际应用中,一个bundle开发者通过实现服务接口来创建一个服务对象,并将这个服务注册到框架服务注册器中。一旦一个bundle以一个接口名注册了一个服务对象,这个关联的服务就能在bundles中通过接口名获得,它的方法能以它的服务接口的方式访问。框架页支持以类名的方式注册服务,所以规范中的服务接口可以被理解为一个接口或一个类(当然一般情况下都是用接口)。
When requesting a service object from the Framework, a bundle can specify the name of the service interface that the requested service object must implement. In the request, the bundle may also specify a filter string to narrow the search.
当一个bundle从框架中请求一个服务对象时,它能指定那个被请求的服务对象必须实现的服务接口的名字,请求过程中,bundle也可以指定一个过滤器字符串来缩小查找范围。
Many service interfaces are defined and specified by organizations such as the OSGi Alliance. A service interface that has been accepted as a standard can be implemented and used by any number of bundle developers.
很多服务接口被OSGi联盟这样的组织定义和指定了,一个被公认为标准的服务接口可以被bundle开发者实现并使用。
例如:(参见org.eclipse.osgi.framework.internal.core.FrameworkCommandProvider)
ServiceReference packageAdminRef =
bundleContext.getServiceReference("org.osgi.service.packageadmin.PackageAdmin");
5.2.3 Registering Services
A bundle publishes a service by registering a service object with the Framework service registry. A service object registered with the Framework is exposed to other bundles installed in the OSGi environment.
一个bundle通过将一个服务对象注册到框架服务注册器来发布一个服务,一个被注册的服务对象被暴露给其他安装了的bundles。
Every registered service object has a unique ServiceRegistration object, and has one or more ServiceReference objects that refer to it. These ServiceReference objects expose the registration properties of the service object, including the set of service interfaces they implement. The ServiceReference object can then be used to acquire a service object that
implements the desired service interface. The Framework permits bundles to register and unregister service objects dynamically. Therefore, a bundle is permitted to register service objects at any time during the STARTING, ACTIVE or STOPPING states.
每个注册的服务对象都有一个唯一的ServiceRegistration对象,并且有一个或多个ServiceReference对象引用它,这些ServiceReference对象暴露服务对象的注册属性,包括它们实现的服务接口,然后可以使用ServiceReference对象来获取实现了服务接口的服务对象。框架允许bundle动态地注册和注销服务对象,因此一个bundle可以在STARTING,ACTIVE或STOPPING状态注册服务对象。
A bundle registers a service object with the Framework by calling one of the BundleContext.registerService methods on its BundleContext object:
• registerService(String,Object,Dictionary) – For a service object registered under a single service interface.
• registerService(String[],Object,Dictionary) – For a service object registered under multiple service interfaces.
一个bundle可以通过调用以下方法注册服务对象:
• registerService(String,Object,Dictionary) – 将一个服务对象注册到一个服务接口名下
• registerService(String[],Object,Dictionary) –将一个服务对象注册到多个服务接口名下
The names of the service interfaces under which a bundle wants to register its service are provided as arguments to the registerService methods. The Framework must ensure that the service object actually is an instance of each specified service interfaces, unless the object is a Service Factory. See Service Factory on page 117.
一个bundle注册它的服务(一个对象)到一个(些)服务接口,这个(些)服务接口的名字做为参数提供给registerService方法。框架必须确保服务对象是这些服务接口的实例,除非这个服务对象是一个ServiceFactory
To perform this check, the Framework must load the Class object for each specified service interface from either the bundle or a shared package. For each Class object, Class.isInstance must be called and return true on the Class object with the service object as the argument.
对于执行这个检查,框架必须为这些来自bundle或共享包的服务接口加载Class对象,调用Class.isInstance方法,服务对象作为参数,必须返回true
The service object being registered may be further described by a Dictionary object, which contains the properties of the service as a collection of key/value pairs.
被注册的服务对象后面的一个被Dictionary对象描述的参数,可能包含了将服务的属性做为一个键值对集合。
The service interface names under which a service object has been successfully registered are automatically added to the service object’s properties under the key objectClass. This value must be set automatically by the Framework and any value provided by the bundle must be overridden.
一个服务对象被成功注册于服务接口的名下,这个(些)接口的名字会被自动添加到服务对象的属性中,键名为objectClass(值为字符串数组类型)。这些值必须由框架自动添加,bundle提供的值必须被覆盖。
If the service object is successfully registered, the Framework must return a ServiceRegistration object to the caller. A service object can be unregistered only by the holder of its ServiceRegistration object (see the unregister() method). Every successful service object registration must yield a unique ServiceRegistration object even if the same service object is registered multiple times.
如果服务对象被成功注册,框架必须返回一个ServiceRegistration对象给调用者。一个服务对象仅仅只能被持有它的ServiceRegistration对象注销。每一次服务对象的成功注册都要伴随生成一个ServiceRegistration对象,即使一个相同的服务对象已经被注册过了。
5.2.4 Early Need for ServiceRegistration Object
The registration of a service object will cause all registered ServiceListener objects to be notified. This is a synchronous notification. This means that such a listener can get access to the service and call its methods before the registerService method has returned the ServiceRegistration object. In certain cases, access to the ServiceRegistration object is necessary in such a callback. However, the registering bundle has not yet received the
ServiceRegistration object. Figure 5.30 on page 111 shows such a sequence.
一个服务对象的注册会使所有注册的ServiceListener对象得到通知(有服务被注册了),这是一个同步通知,这就意味着一个监听器能在registerService方法返回ServiceRegistration对象之前访问服务并调用服务的方法。在某些情况下,在这样的回调方法中访问ServiceRegistration对象是有必要的,但是注册服务的bundle此时并没有收到ServiceRegistration对象。
In a case as described previously, access to the registration object can be obtained via a ServiceFactory object. If a ServiceFactory object is registered, the Framework must call-back the registering bundle with the ServiceFactory method getService(Bundle,ServiceRegistration). The required ServiceRegistration object is passed as a parameter to this method.
在前面描述的例子中,可以通过ServiceFactory对象来访问注册对象,如果一个ServiceFactory对象被注册,框架必须以ServiceFactory.getService(Bundle,ServiceRegistration)方法回调注册bundle。ServiceRegistration对象做为参数传入这个方法中。
5.2.5 Service Properties
Properties hold information as key/value pairs. The key must be a String object and the value should be a type recognized by Filter objects (see Filters on page 116 for a list). Multiple values for the same key are supported with arrays ([]) and Collection objects.
The values of properties should be limited to primitive or standard Java types to prevent unwanted inter bundle dependencies. The Framework cannot detect dependencies that are created by the exchange of objects between bundles via the service properties.
The key of a property is not case sensitive. ObjectClass, OBJECTCLASS and objectclass all are the same property key. A Framework must return the key in ServiceReference.getPropertyKeys in exactly the same case as it was last set. When a Dictionary object that contains keys that only differ in case is passed, the Framework must raise an exception.
The service properties are intended to provide information about the service object. The properties should not be used to participate in the actual function of the service. Modifying the properties for the service registration is a potentially expensive operation. For example, a Framework may pre-process the properties into an index during registration to speed up later lookups.
The Filter interface supports complex filtering; it can be used to find matching service objects. Therefore, all properties share a single name space in the Framework service registry. As a result, it is important to use descriptive names or formal definitions of shorter names to prevent conflicts. Several OSGi specifications reserve parts of this name space. All properties starting with the prefix service. and the property objectClass are reserved for use by
OSGi specifications.
Table 5.9 Standard Service Properties contains a list of pre-defined properties.
Table 5.9 Standard Service Properties
Property Key Type Constants Property Description
service.id Long SERVICE_ID Every registered service object is
assigned a unique service.id by the
Framework. This number is added
to the service object’s properties.
The Framework assigns a unique
value to every registered service
object that is larger than values provided
to all previously registered
service objects.
service.pid String SERVICE_PID The service.pid property optionally
identifies a persistent, unique
identifier for the service object. See
Persistent Identifier (PID) on page
113.
service.ranking Integer SERVICE_RANKING When registering a service object, a
bundle may optionally specify a
service.ranking number as one of
the service object’s properties. If
multiple qualifying service interfaces
exist, a service with the highest
SERVICE_RANKING number, or
when equal to the lowest
SERVICE_ID, determines which service
object is returned by the Framework.
service.vendor String SERVICE_VENDOR This optional property can be used
by the bundle registering the service
object to indicate the vendor.
5.2.6 Persistent Identifier (PID)
The purpose of a Persistent Identifier (PID) is to identify a service across Framework restarts. Services that can reference the same underlying entity every time they are registered should therefore use a service property that contains a PID. The name of the service property for PID is defined as service.pid. The PID is a unique identifier for a service that persists over
multiple invocations of the Framework. For a given service, the same PID should always be used. If the bundle is stopped and later started, the same PID must always be used.
The format of the PID should be:
pid ::= symbolic-name // See 1.3.2
A PID must be unique for each service. A bundle must not register multiple services with the same PID, nor should other bundles use the same PID. If this happens, it is an error condition.
Persistent Identifier (PID)的目的是为了在框架重启后识别一个服务,每次服务注册时,都引用同一个实体,因此应当使用一个包含了PID的服务属性。服务属性的名字被定义为service.pid。
5.2.7 Locating Services
In order to use a service object and call its methods, a bundle must first obtain a ServiceReference object. The BundleContext interface defines two methods a bundle can call to obtain ServiceReference objects from the Framework:
为了使用一个服务对象并调用它的方法,一个bundle必须首先获得一个ServiceReference对象。接口BundleContext定义了2个方法来从框架中获取ServiceReference对象:
• getServiceReference(String) – This method returns a ServiceReference object to a service object that implements, and was registered under, the name of the service interface specified as String. If multiple such service objects exist, the service object with the highest SERVICE_RANKING is returned. If there is a tie in ranking, the service object with the lowest
SERVICE_ID (the service object that was registered first) is returned.
• getServiceReference(String) – 这个方法返回一个到一个服务对象的ServiceReference对象,这个服务对象实现并注册于参数中String指定的服务接口,如果有多个这样的服务对象存在,具有最高SERVICE_RANKING的服务对象被返回。如果有2个相同的SERVICE_RANKING,那么具有最低SERVICE_ID(先被安装的)的服务对象被返回。
• getServiceReferences(String,String) – This method returns an array of ServiceReference objects that:
• Implement and were registered under the given service interface.
• Satisfy the search filter specified. The filter syntax is further explained in Filters on page 116.
Both methods must return null if no matching service objects are returned. Otherwise, the caller receives one or more ServiceReference objects. These objects can be used to retrieve properties of the underlying service object, or they can be used to obtain the actual service object via the BundleContext object.
如果没有匹配的服务对象,这两个方法必须返回null,否则,调用者将收到1个或多个ServiceReference对象。这些对象能被用来获取服务对象属性,或是通过BundleContext来获取真正的服务对象。
Both methods require that the caller has the required ServicePermission[<name>, GET] to get the service object for the specified service interface names. If the caller lacks the required permission, these methods must return null.
这两个方法需要调用者有ServicePermission[<name>, GET]权限通过制定的服务接口名去获得服务对象,如果调用者没有这个权限,这两个方法必须返回null。
5.2.8 Getting Service Properties
To allow for interrogation of service objects, the ServiceReference interface defines these two methods:
• getPropertyKeys() – Returns an array of the property keys that are available.
• getProperty(String) – Returns the value of a property.
Both of these methods must continue to provide information about the referenced service object, even after it has been unregistered from the Framework. This requirement can be useful when a ServiceReference object is stored with the Log Service.
5.2.9 Getting Service Objects
The BundleContext object is used to obtain the actual service object so that the Framework can manage dependencies. If a bundle retrieves a service object, that bundle becomes dependent upon the life cycle of that registered service object. This dependency is tracked by the BundleContext object used to obtain the service object, and is one reason that it is important to be careful when sharing BundleContext objects with other bundles.
BundleContext对象用于获取真实的服务对象,因此框架要管理它们的依赖关系。如果一个bundle获得了一个服务对象,那么这个bundle将依赖于那个注册的服务对象的生命周期,这个依赖关系由用于获取服务对象的BundleContext去跟踪,这样做的原因是防止bundles间共享BundleContext。
The method BundleContext.getService(ServiceReference) returns an object that implements the interfaces as defined by the objectClass property.
方法BundleContext.getService(ServiceReference)返回一个实现了属性中"objectClass"指定接口的对象。
This method has the following characteristics:
这个方法有以下特性:
• Returns null if the underlying service object has been unregistered.
• 如果服务对象已经被注销,返回null
• Determines if the caller has ServicePermission[<interface name>,GET], to get the service object using at least one of the service interfaces under which the service was registered. This permission check is necessary so that ServiceReference objects can be passed around freely without compromising security.
• 决定调用者是否有ServicePermission[<interface name>,GET]权限使用至少其中一个服务接口去得到一个注册于该服务接口名下的服务对象。这个检查是有必要的,这样才能使ServiceReference对象自由传递而不需要考虑安全问题。
• Increments the usage count of the service object by one for this BundleContext object.
• 这个BundleContext对象使用这个服务对象的次数加1.
• If the service object does not implement the ServiceFactory interface, it is returned. Otherwise, if the bundle context’s usage count of the service object is one, the object is cast to a ServiceFactory object and the getService method is called to create a customized service object for the calling bundle which is then returned. Otherwise, a cached copy of this
customized object is returned. See Service Factory on page 117 for more information about ServiceFactory objects.
• 如果服务对象没有实现ServiceFactory接口,它直接被返回。否则,如果bundlecontext使用这个服务对象的次数是1,这个对象将被cast为一个ServiceFactory对象,getService方法被调用来为调用bundle生成一个定制的服务对象,如果次数不是1,一个缓存的定制对象被返回。
5.2.10 Information About Services
The Bundle interface defines these two methods for returning information pertaining to service usage of the bundles:
接口Bundle定义了2个方法用于返回bundles使用的服务的相关信息
• getRegisteredServices() – Returns the service objects that the bundle has registered with the Framework.
• getRegisteredServices() – 返回bundle已经注册的服务对象。
• getServicesInUse() – Returns the service objects that the bundle is using.
• getServicesInUse() – 返回bundle使用的服务对象。
5.3 Service Events
• ServiceEvent – Reports registration, unregistration, and property changes for service objects. All events of this kind must be delivered synchronously. The type of the event is given by the getType() method, which returns an int. Event types can be extended in the future;
unknown event types should be ignored.
• ServiceListener – Called with a ServiceEvent when a service object has been registered or modified, or is in the process of unregistering. A security check must be performed for each registered listener when a ServiceEvent occurs. The listener must not be called unless the bundle which registered the listener has the required ServicePermission[<interface name>,GET] for at least one of the interfaces under which the service object is registered.
• ServiceEvent – 报告服务对象的注册,注销和属性改变,所有这个类型的事件必须被同步发送。事件的类型通过getType()方法获得,返回的是一个int。事件类型可以被扩展,未知的时间类型应该被忽略。
• ServiceListener –附带一个ServiceEvent做为参数被调用于一个服务对象被注册或改变,或是在注销时,
。当一个ServiceEvent发生时,必须为每一个注册的监听器执行安全检查,如果监听器对一个服务接口没有ServicePermission[<interface name>,GET]权限,监听器必须不能被调用。
A bundle that uses a service object should register a ServiceListener object to track the availability of the service object, and take appropriate action when the service object is unregistering.
一个使用服务对象的bundle应该注册一个ServiceListener对象来跟踪这个服务对象的有效性,在服务对象注销时采取合适的处理。
5.4 Stale References
The Framework must manage the dependencies between bundles. This management is, however, restricted to Framework structures. Bundles must listen to events generated by the Framework to clean up and remove stale references.
框架必须管理bundles间的依赖关系,但是这个管理限制于框架结构。bundles必须监听框架生成的事件,清理和移除失效的引用。
A stale reference is a reference to a Java object that belongs to the class loader of a bundle that is stopped or is associated with a service object that is unregistered. Standard Java does not provide any generic means to clean up stale references, and bundle developers must analyze their code carefully to ensure that stale references are deleted.
一个失效的引用是指,引用了一个属于停止了的bundle的classloader或是关联了一个已经注销了的java对象。标准java没有提供一个通用方法去清理失效的引用,bundle开发者必须仔细分析代码以确保失效的引用被删除。
Stale references are potentially harmful because they hinder the Java garbage collector from harvesting the classes, and possibly the instances, of stopped bundles. This may result in significantly increased memory usage and can cause updating native code libraries to fail. Bundles using services are strongly recommended to use either the Service Tracker or Declarative
Services.
失效的引用是一个潜在的危险,因为它们妨碍了java gc回收停止了的bundles的对象实例,这可能导致增加内存的使用和引起本地代码库更新失败。对于bundle使用services,强烈推荐使用Service Tracker或Declarative Services。
Service developers can minimize the consequences of (but not completely prevent) stale references by using the following mechanisms:
• Implement service objects using the ServiceFactory interface. The methods in the ServiceFactory interface simplify tracking bundles that use their service objects. See Service Factory on page 117.
• Use indirection in the service object implementations. Service objects handed out to other bundles should use a pointer to the actual service object implementation. When the service object becomes invalid, the pointer is set to null, effectively removing the reference to the actual service object.
服务开发者可以使用以下机制来尽可能的减少失效的引用:
• 服务对象实现ServiceFactory接口,接口ServiceFactory中的方法简化了对使用服务对象的bundles的跟踪
• 使用简介引用服务对象的实现。bundles注册的服务应该使用一个指针指向真是的服务对象的实现,当服务对象不可用时,这个指针设置为null,有效的移除对真实服务对象的引用。
The behavior of a service that becomes unregistered is undefined. Such services may continue to work properly or throw an exception at their discretion. This type of error should be logged.
一个服务注销的行为没有定义,这些服务可能会继续工作或是随意抛出一个exception,错误类型应该被记录。
5.5 Filters
The Framework provides a Filter interface, and uses a filter syntax in the getServiceReferences method that is defined in Filter Syntax on page 29. Filter objects can be created by calling BundleContext.createFilter(String) or FrameworkUtil.createFilter(String) with the chosen filter string. The filter supports the following match methods:
• match(ServiceReference) – Match the properties of the Service Reference performing key lookup in a case insensitive way.
• match(Dictionary) – Match the entries in the given Dictionary object performing key lookup in a case insensitive way.
• matchCase(Dictionary) – Match the entries in the given Dictionary object performing key lookup in a case sensitive way.
框架提供了一个Filter接口,并在方法getServiceReferences 中使用了一个过滤器(filter)语法,Filter 对象可以通过调用BundleContext.createFilter(String)或FrameworkUtil.createFilter(String)以一个过滤器字符串为参数来创建。filter 支持以下匹配方法:
• match(ServiceReference) – 匹配ServiceReference的属性,不区分大小写
• match(Dictionary) – 匹配给定的Dictionary 对象实体,不区分大小写
• matchCase(Dictionary) – 匹配给定的Dictionary 对象实体,区分大小写
A Filter object can be used numerous times to determine if the match argument, a ServiceReference object or a Dictionary object, matches the filter string that was used to create the Filter object.
一个Filter对象可以无限使用于决定参数ServiceReference 对象或Dictionary 对象是否匹配创建Filter对象时的过滤器字符串。
This matching requires comparing the value string in the filter to a target object from the service properties or dictionary. This comparison can be executed with the Comparable interface if the target object’s class implements a constructor taking a single String object and the class implements the Comparable interface. That is, if the target object is of class Target, the class Target must implement:
• A constructor Target(String)
• Implement the java.lang.Comparable interface
这个匹配需要在过滤器中比对一个目标对象中的字符串值与服务属性或字典对象中的字符串值,如果目标对象实现了接口Comparable并有以一个String对象为参数的构造函数,可以使用Comparable来执行比对
If the target object does not implement java.lang.Comparable, the =, ~=, <=, >= operators must return only true when the objects are equal (using the equals(Object) method). The Target class does not need to be a public class.
如果目标对象没有实现Comparable接口,=, ~=, <=, >= 操作只有当2个对象相等(使用equals(Object) 方法)的时候才返回true
The following example shows how a class can verify the ordering of an enumeration with a filter.
public class B implements Comparable {
String keys[] = {"bugs", "daffy", "elmer", "pepe"};
int index;
public B(String s) {
for ( index=0; index<keys.length; index++ )
if ( keys[index].equals(s) )
return;
}
public int compareTo( Object other ) {
B vother = (B) other;
return index - vother.index;
}
}
The class could be used with the following filter: (!(enum>=elmer)) -> matches bugs and daffy
The Filter.toString method must always return the filter string with unnecessary white space removed.
5.6 Service Factory
A Service Factory allows customization of the service object that is returned when a bundle calls BundleContext.getService(ServiceReference).
当一个bundle调用BundleContext.getService(ServiceReference)方法时,ServiceFactory允许返回的是一个定制的服务对象。
Often, the service object that is registered by a bundle is returned directly. If, however, the service object that is registered implements the ServiceFactory interface, the Framework must call methods on this object to create a unique service object for each distinct bundle that gets the service.
通常,由一个bundle注册的服务对象会直接返回。但是如果这个服务对象实现了ServiceFactory接口,框架必须调用这个对象中的方法来为各个不同的bundle创建一个唯一的服务对象。
When the service object is no longer used by a bundle – for example, when that bundle is stopped – then the Framework must notify the ServiceFactory object.
当服务对象不再被bundle使用时 - 例如,当bundle停止时 - 框架必须通知ServiceFactory对象。
ServiceFactory objects help manage bundle dependencies that are not explicitly managed by the Framework. By binding a returned service object to the requesting bundle, the service can be notified when that bundle ceases to use the service, such as when it is stopped, and release resources associated with providing the service to that bundle.
ServiceFactory对象帮助管理那些框架并不明确管理的bundle的依赖关系(例如服务注册引发的依赖关系),通过将一个服务对象绑定到注册它的bundle,这个服务会在bundle终止使用它时得到通知,例如当bundle停止,并释放与服务相关联的资源时。
The ServiceFactory interface defines the following methods:
接口ServiceFactory定义了以下方法:
• getService(Bundle,ServiceRegistration) – This method is called by the Framework if a call is made to BundleContext.getService and the following are true:
• getService(Bundle,ServiceRegistration) – 如果是通过BundleContext.getService调用,并满足以下条件,这个方法将被框架调用来返回一个服务对象
• The ServiceReference argument to BundleContext.getService refers to a service object that implements the ServiceFactory interface.
• BundleContext.getService中的参数ServiceReference对象引用的服务对象实现了接口ServiceFactory
• The bundle’s usage count of that service object is zero; that is, the bundle currently does not have any dependencies on the service object.
• bundle中的这个服务对象的使用次数是0,也就是说目前这个bundle对这个服务对象还没有任何依赖关系。
The call to BundleContext.getService must be routed by the Framework to this method, passing to it the Bundle object of the caller. The Framework must cache the mapping of the requesting bundle-to-service, and return the cached service object to the bundle on future calls to
BundleContext.getService, as long as the requesting bundle's usage count of the service object is greater than zero. The Framework must check the service object returned by this method. If it is not an instance of all the classes named when the service factory was registered, null is returned to the caller that called getService. This check must be done as specified in Registering Services on page 110.
如果以上条件成立,框架必须将对BundleContext.getService的调用路由到这个方法(ServiceFactory.getService(Bundle,ServiceRegistration)),将调用者的Bundle对象传入。框架必须缓存bundle对服务的请求的映射关系,当下次这个bundle再次请求这个服务时,直接返回缓存中的服务对象,并且要使请求的bundle对这个服务的使用次数大于0.框架必须检查这个方法返回的服务对象,如果这个对象(实现了ServiceFactory接口)不是注册它时所指定的类名(这个类名可以是接口,也可以是具体类)的实例,必须返回null。
• ungetService(Bundle,ServiceRegistration,Object) – This method is called by the Framework if a call is made to BundleContext.ungetService and the following are true:
• ungetService(Bundle,ServiceRegistration,Object) – 如果是通过BundleContext.ungetService调用,并满足以下条件,这个方法将被框架调用
• The ServiceReference argument to BundleContext.ungetService refers to a service object that implements the ServiceFactory interface.
• BundleContext.ungetService的参数ServiceReference对象引用的服务对象实现了ServiceFactory接口
• The bundle’s usage count for that service object must drop to zero after this call returns; that is, the bundle is about to release its last dependency on the service object.
• 这个调用返回之后,bundle对这个服务对象的使用次数减少到0;也就是说,bundle会释放它对这个服务对象的全部依赖关系。
The call to BundleContext.ungetService must be routed by the Framework to this method so the ServiceFactory object can release the service object previously created.
Additionally, the cached copy of the previously created service object must be unreferenced by the Framework so it may be garbage collected.
如果以上条件成立,框架必须将对BundleContext.ungetService 的调用路由到这个方法(ServiceFactory.ungetService(Bundle,ServiceRegistration)),使ServiceFactory对象能释放以前生成的服务对象。
另外,以前生成的服务对象的缓存片嘟啊必须被框架解除引用,使之可以被gc
5.7 Releasing Services
In order for a bundle to release a service object, it must remove the dynamic dependency on the bundle that registered the service object. The BundleContext interface defines a method to release service objects: ungetService(ServiceReference). A ServiceReference object is passed as the argument of this method.
为了使一个bundle释放一个服务对象,它必须移除与注册了服务对象的bundle上的动态依赖关系。接口BundleContext定义了一个释放服务对象的方法:ungetService(ServiceReference),参数是一个ServiceReference对象。
This method returns a boolean value:
• false if the bundle’s usage count of the service object is already zero when the method was called, or the service object has already been unregistered.
• true if the bundle’s usage count of the service object was more than zero before this method was called.
这个方法返回一个boolean值:
• false - 当这个方法被调用时,bundle中对服务对象的使用次数是0,或者服务对象已经被注销。
• true - 这个方法调用时,bundle中对服务对象的使用次数大于0
5.8 Unregistering Services
The ServiceRegistration interface defines the unregister() method to unregister the service object. This must remove the service object from the Framework service registry. The ServiceReference object for this ServiceRegistration object can no longer be used to access the service object.
ServiceRegistration接口定义了unregister()方法用于注销服务对象,这个方法必须从框架的服务注册器中移除这个服务对象。ServiceRegistration对象的ServiceReference对象将不再能用来访问服务对象。
The fact that this method is on the ServiceRegistration object ensures that only the bundle holding this object can unregister the associated service object. The bundle that unregisters a service object, however, might not be the same bundle that registered it. As an example, the registering bundle could have passed the ServiceRegistration object to another bundle, endowing that bundle with the responsibility of unregistering the service object. Passing ServiceRegistration objects should be done with caution.
ServiceRegistration对象中的这个方法实际上确保了只有持有这个对象的bundle能够注销这个关联着的服务对象(注:之前提到不需要在Activator中手动注销服务,因为服务的注销由框架管理,当Bundle停止时,它的BundleContext会注销服务,参见org.eclipse.osgi.framework.internal.core.BundleContextImpl.close)。注销一个服务的bundle可能不是注册它的那个bundle,例如,注册服务的bundle可以将ServiceRegistration对象传给别的bundle,由那个bundle负责注销服务对象。传递ServiceRegistration对象应慎重。
After ServiceRegistration.unregister successfully completes, the service object must be:
ServiceRegistration.unregister成功完成后,服务对象必须:
• Completely removed from the Framework service registry. Therefore, ServiceReference objects obtained for that service object can no longer be used to access the service object. Calling BundleContext.getService method with the ServiceReference object must return null.
• 完全从框架服务注册器中移除,因此用于获取服务对象的ServiceReference对象无法再用来访问这个服务对象,BundleContext.getService方法返回null。
• Unregistered, even if other bundles had dependencies upon it. Bundles must be notified of the unregistration through the publishing of a ServiceEvent object of type ServiceEvent.UNREGISTERING. This event is sent synchronously in order to give bundles the opportunity to release the service object. After receiving an event of type ServiceEvent.UNREGISTERING, a bundle should release the service object and release any references it has to this object, so that the service object can be garbage collected by the Java VM.
• 被注销,即使其他bundles还在依赖它。bundles必须通过发布的类型为ServiceEvent.UNREGISTERING的ServiceEvent对象得到通知。这个事件发送是同步的,以便bundles有机会释放服务对象。收到ServiceEvent.UNREGISTERING事件后,bundle应该释放服务对象并释放这个服务对象对这个bundle的引用.
• Released by all using bundles. For each bundle whose usage count for the service object remains greater than zero after all invoked ServiceListener objects have returned, the Framework must set the usage count to zero and release the service object.
• 被所有使用它的bundles释放(事件通知)。在所有ServiceListener得到通知之后,对于每个对这个服务对象的使用次数仍然大于0的bundle,框架必须释放服务对象,并将使用次数设置为0.
5.9 Multiple Version Export Considerations
Allowing multiple bundles to export a package with a given name causes some complications for Framework implementers and bundle programmers: The class name no longer uniquely identifies the exported class. This affects the service registry and permission checking.
允许多个bundles输出一个包增加了框架实现和bundle开发者的复杂度,因为类名不再是输出类的唯一标识符,这会影响服务注册和权限检查。
5.9.1 Service Registry
Bundles must not be exposed to services for which there are conflicting class loaders. A bundle that gets a service should be able to expect that it can safely cast the service object to any of the associated interfaces or classes under which the service was registered and that it can access. NoClassCastExceptions should occur because those interfaces do not come from the same class loader. The service registry must therefore ensure that bundles can only see services that are not incompatible with them. A service is not incompatible with the bundle getting the service when that bundle is not wired to another source class loader for this interface package than the bundle registering the service. That is, it is either wired to the same source
class loader or it has no wire for that package at all.
在class loaders冲突的情况下,bundles不能被暴露给服务。获取一个服务的bundle应该被认为是能安全的将服务对象cast到关联的接口或类。如果接口和服务对象不是来自同一个class loader,应该抛出NoClassCastExceptions。因此服务注册器必须确保bundles仅仅能看到与之兼容的服务。当获取服务的bundle没有为这个接口连接到其他源class loader时(没有连接到其他bundle),一个服务与获取的服务的bundle兼容。也就是说,要嘛接口和服务对象连接到同一个源class loader,要嘛根本就不连接它们(无法获取服务对象)。
It is paramount that bundles are not accidentally confronted with incompatible services. Therefore, the following methods need to filter ServiceReference objects depending on the incompatibility of the interfaces with the calling bundle. The bundle is identified by the used BundleContext:
• getServiceReference(String) – Only return a Service Reference that is not incompatible with the calling bundle for the specified interface.
• getServiceReferences(String,String) – Only return Service References that are not incompatible with the calling bundle for the specified interface.
有一点很重要,bundles绝对不能意外的遇到不兼容的服务,因此,以下方法需要根据接口与调用bundle的兼容性来过滤ServiceReference对象,使用BundleContext来识别bundle
• getServiceReference(String) – 仅仅返回一个ServiceReference对象,它与调用bundle指定的接口兼容
• getServiceReferences(String,String) –返回多个ServiceReference对象。
The getAllServiceReferences(String,String) provides access to the service registry without any compatibility restrictions. Services acquired through this method can cause Class Cast Exceptions for the correct class names.
The ServiceReference isAssignableTo(Bundle,String) method is also available to test if the bundle that registered the service referenced by this ServiceReference and the specified bundle are both wired to same source for the specified interface.
5.9.2 Service Events
Service events must only be delivered to event listeners that are not incompatible with the Service Reference.
服务事件必须被发送到与ServiceReference兼容的事件监听器。
Some bundles need to listen to all service events regardless the compatibility issues. A new type of ServiceListener is therefore added: AllServiceListener. This is a marker interface; it extends ServiceListener. Listeners that use this marker interface indicate to the Framework that they want to see all services, including services that are incompatible with them.
一些bundles需要监听所有服务事件而不想关心兼容性问题,因此,添加了一个新的对象类型: AllServiceListener。这是一个标记接口,它继承了ServiceListener。使用这个标记接口的监听器表示它想要监听所有的服务,包括那些不兼容的服务。