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。使用這個標記接口的監聽器表示它想要監聽所有的服
務,包括那些不兼容的服務。