簡介
SLEE 是一個容器標準,目標是提供移動技術與企業技術之間的整合。該標準類似於 EJB,不過是用於各種面向事件的應用程式,例如 IP 電話服務、分散式互動模擬/監控/控制等。Mobicents 是第一個而且是目前唯一開源並被 JAIN SLEE 1.0 認定的產品,它從交換協定構造上基於 JAIN-SIP。
前言
Mobicents 是一個專業開源的 VoIP 中間件平台。Mobicents 是第一個而且是目前唯一開源並被 JAIN SLEE 1.0 認定的產品,它從交換協定構造上基於 JAIN-SIP。
作用
JAIN SLEE 是一個以事件為驅動的中間件,採用了各個服務單元(Sbb)訊息機制,減少了在事物處理上的等待延遲,其工作方式是從外部協定資源掃描事件狀態,然後將這些事件遞交到各個處理單元去,可以以它為核心設計成網關和網守,軟交換上層的套用伺服器,媒體伺服器等多種設備,同時適配多種交換協定。
詳細介紹
以下分成 10 個部分來對 Mbicents-SLEE 進行詳細介紹:
1. 資源適配器(Resource Adaptor)體系;
2. JAIN-SIP;
3. 事件和事件類型(Events),事件引導(Routing);
4. 行為實體(Activity)和行為實體上下文(Activity Context);
5. SBB部件和SBB實體;
6. 數據供應(Provisioned Data);
7. SLEE的一些工具(facility);
8. 服務和部署(Service and Deployment);
9. 套用範例(SIP代理伺服器,信令網關);
10. 使用elipslee來進行SBB的開發;
下面展示了Mobicents Docs中的一個體系分布圖:
圖1 . SLEE的體系分布圖
1> SBB 服務管理單元(Sbb Service Management):這個部分面向上層的套用,也就是 Service Block Building 的構造和部署的主要部分,其中包含了對象持久性(Persistence),類似 EJB 的CMP 一樣,對數據對象的持久性(包括生存期和資料庫連線等等)由 SLEE 容器自動完成的,SBB 分成 Sbb 實體和 Sbb 對象兩個組成。對整個 Sbb 的服務管理單元來說,包含有 Sbb 工廠,持久性管理,Sbb 對象池管理,服務部署者,這些對於實際的使用者而言是不可見的。用戶的套用部署檔案是 sbb.jar,而用戶服務描述是 service.xml。
2> Sbb 運行環境(Sbb Runtime):Sbb 運行環境就是Sbb的執行體,核心是事件導向單元--Event Router,(獲得事件並且分配導入到指定的 Sbb 中去),SLEE 端點管理(連線資源適配器產生事件送達端點),通過上下文(Context)方式來實現各個實體之間的聯繫(參看圖7),和 Sbb服務管理單元之間的接口是 ActivityContext(以下為活躍實體或者行為實體上下文),用於表示獨立的事件接口;和資源適配器之間的接口是 Activity,也就是行為實體,具體事件的封裝,例如 SIP 的註冊事件(SIP Register),這個事件會引發 Sbb 的相關註冊服務(例如 RegisteraSbb);另一個接口是 SLEE Activity,這個是 SLEE 內部的行為實體,例如一些內部的工具產生的行為實體,例如定時器事件(Timer Event)和用於調試的 Trace 事件。
3> SLEE 的一些工具:和 J2EE 中的工具一樣,提供了一些工具來使用,工具在 SLEE 中的定義是一些標準的功能組件,他們的提供了一些預定義的接口為套用提供服務,其中包括了Adress,Profile,Alarm,Naming。
4> 資源適配器(RA),用於具體的協定在SLEE上的封裝,例如(SCAP,SS7,SIP,MGCP,H.323)當然也可以是自己的私有協定,封裝的方式可以參看Mobicents官方網站的一些介紹,協定和SLEE Run-time的接口就是具體的行為實體,也就是事件的封裝, 用戶定義的資源適配器部署檔案是RA.jar在本文中SIP資源適配器的部署檔案是sip-local-ra.jar和sip-type-ra.jar。
一. 資源適配器(Resource Adaptor)體系
1.Mobicents資源適配器的概述以及定義和套用模式:
備註:Mobicents 中的資源適配器提供了非常方便的接口以便實現各種協定資源在 SLEE 上的組裝,目前在 1.0a 和 1.0b中都只完成了 SIP 協定和 TCAP 協定,事實上後者的意義在於將 SIP 模擬作為 NSP 層而採用的套用層協定。
資源適配器主要是指的網路設備和協定棧本身,和狀態機的有連線協定,例如我們在下面將詳細介紹的JAIN-SIP 以及其他支持JAVA語言的呼叫代理協定, JCC API,Parlay/OSA 等。
資源適配器分成三個範疇,
a. 資源適配器類型(Resource adaptor type);
b. 資源適配器對象;
c. 資源適配器實體(entity);
2. 協定棧的資源在 SLEE 上的綁定:
在 Mobicents1.0a 上綁定了兩個資源實體就是 JAIN-SIP 的資源實體(SIpRA),和 JAIN SLEE TCK,下面我們根據它的第三方範例 (Third-Party) 註冊機(Registar)來簡單介紹它的資源綁定模式:
首先是協定棧描述,就是 SIP 在 Sbb 服務上的描述,在 sbb-jar.xml 檔案中會體現,這個檔案是 SBB 的部署檔案,可以理解為 J2EE 中的 ejb-jar.xml 檔案。
如Registrar中的:
jain-sip
//JAIN SIP的資源適配器類型
javax.sip
1.1
在JNDI中的實體上下文工廠的綁定,SBB的開發者通過lookup來調用
slee/resources/jainsip/1.1/acifactory
定義了SBB所依靠的一個定義資源適配器對象名稱在JNDI上綁定的類型
slee/resources/jainsip/1.1/provider
定義了resource-adaptor-object-name中表示的資源實體對象SIPRA
SIPRA
其中:
資源適配器對象名稱就是slee/resources/jainsip/1.1/provider
資源適配器實體的名稱SIPRA ,實體本身使用專門的工具DeploySipRA.sh將會對SIPRA進行創建和部署,腳本中如下描述:
call %JBOSS_HOME%\bin\SleeCommandInterface.bat -createRaEntity "ResourceAdaptorID[jainsip#NIST#1.1]" SIPRA
類型名稱是:jain-sip
3.協定棧工廠的調用 :
在Sbb中調用lookup() 方法時都會執行一次新查找獲得資源實體工廠,這裡會返回工廠實例SipFactoryProvider,包含了SBB需要對資源實體訪問時候需要訪問的資源實體工廠名稱,例如:
fp = (SipFactoryProvider) sbbEnv.lookup("slee/resources/jainsip/1.1/provider");
SIP協定工廠,用於生產SIP的訊息體(Message),SIP的頭(Header),SIP的JAIN-SIP的ServerTransaction/ClientTransaction(交易的狀態機,和每次會話--Cseq對應),SIP訊息傳送傳送者和偵聽事件的偵聽點。
4.行為實體上下文工廠的調用:
,這裡是行為實體上下文工廠接口在JNDI上的綁定,目的是為了Sbb產生行為實體接口的,SBB通過lookup()方式訪問行為實體上下文接口的環境入口,而行為實體上下文接口的工廠的接口(比較拗口,可以理解為一個對象工廠的接口就好了)是在中體現出來,在對SBB的服務進行初始化時候,工廠和JNDI上綁定的名字相對應(sbb-jar.xml中),如resource-adaptor-type-jar.xml中:
org.mobicents.slee.resource.sip.SipActivityContextInterfaceFactory
查找一個行為實體上下文接口工廠:
acif = (SipActivityContextInterfaceFactory)
myEnv.lookup("slee/resources/jainsip/1.1/acifactory")
SBB需要對資源實體活動體上下文接口工廠進行訪問獲得行為實體的接口,例如傳送一個SIP的訊息的有狀態訊息(INVITE訊息)那么sbb就需要獲得一個行為實體上下文接口,與創建的Sbb和這個行為實體接口綁定,維持這個有狀態會話。
關於行為實體的概念,是SLEE中的重要的概念,對於它的理解可以看作對應於一個SIP的會話狀態機,一般用SIP訊息中的Branch ID作為一個"種子"來生成一個行為實體的狀態機,根據這個會話將不同的事件導向到對應的SBB中,在後續將詳細介紹,的上下文(ActivityContextInterface)是可以在Sbb間共享的,通過共享可以獲得訊息的參數,如via,to,from,contact,CallID,Cseq;在SLEE中規定定義一些Set/Get方法來對這些參數進行訪問,參看註冊機中的RegistrarActivityContextInterface中的Set/Get接口方法。
二.JAIN-SIP的簡單介紹
1.什麼是JAIN-SIP:
綜合網路的Java 套用編程接口(JAIN,Java API for Integrated Networks)是一組基於Java技術的API,這些接口將業務可移植性、網路聚合以及安全的網路接入引進電話網和數據網路,使得在Java平台上快速開發下一代電信產品和服務成為可能,在Mobicents中以Jain-sip作為Resource Adaptor。
在JAIN SIP API體系結構中,為所有SIP訊息的報頭定義了類,並藉助提供者/監聽者接口,將用於處理報文的JavaBeans體系結構的接口定義為事件。
Jain-SIP是一個標準的JAVA的SIP協定棧的interface,它分成以下幾個部分:
a. 標準的協定棧的接口;
b. 標準的SIP訊息接口;
c. 標準的SIP訊息狀態機和事件的觸發。
2. 從JAIN-SIP到SLEE中的事件傳導機制:
以下仍然以Registar為例子簡要介紹SLEE中對SIP訊息(或者是事件)的管理以及處理句柄的調用。見圖2,分成事件和協定兩個部分:
事件部分:也就是RFC3261中的事件信息, REGISTER,INVITE等,EventRouter將事件導向到對應的的SBB中的事件處理回調中去(onRegistar),processinitialevents被EventRouter調用,目的是找到處理對應事件的SBB,RegisterSbb是處理對象的SBB。
協定部分:SIP Stack也就是協定棧的部分, SipResourceAdaptor是Resource Adaptor的SIP實例化,Event表示了當前的SIP會話的行為實體,從這裡可以獲得Jain-SIP的服務端會話交易用於處理偵聽訊息的處理句柄(在下面會有介紹),Event Type是JAIN-SIP訊息類型,EventObject是傳遞到SBB實體時候對JAIN-SIP訊息進行的封裝。
圖2.一個註冊機的事件交易過程
3.JAIN-SIP中的重要類介紹:
1> Siplistener
概述:
這個類代表SIP協定的負責偵聽的應用程式端,這個接口定義了一個偵聽端,接收處理從SipProvider提交的SIP事件訊息,是一個抽象的偵聽執行緒。
結構:
每個SIPStack或每個IP位址對應一個的Siplistener,而Siplistener與SipProvider的關係是一對多的關係。
2> SipFactory
SIPFactory是一個單類,用單一方式得到這個SipStack套用的執行權。SIPFactory單一的實例能用得到實例的方法(或者Singleton)而被得到。通過在SIPFactory里調用合適構造方法,一個代表被叫端的對象能從SIPFactory得到。創造一個被叫的SipStack,這樣套用將可以調用SipStack中的方法。
3> ServerTransaction
概述:
ServerTransaction可以通常被理解為一個會話狀態機,SipProvider用來處理接收SIP事件和訊息序列,將接收到訊息傳送到SipListener(偵聽方法)的processRequest或者processResponse回調,通過用戶代理伺服器傳送回應信息給應用程式。這個類讓應用程式能傳送一個回應對應SipListener收到的請求。
方法:
ServerTransaction中的方法:
sendResponse
套用希望傳送一個回響時候,它創立一個來自MessageFactory創造的回應,然後回應傳送到ServerTransaction的sendResponse方法。
4> ClientTransaction
概述:
ClientTransaction套用可以理解為傳送INVITE信息到UAS。ClientTransaction也用從SipListener接收到的回應進行匹配。和ServiceTransaction相對應。
方法:
ClientTransaction的方法:
Request createAck()
通過ClientTransaction創造一個關於當前的請求的正確應答。
void sendRequest()用於傳送創建的請求訊息。
這個類的調用意味著上層的套用是UAC。
圖3. JAIN SIP 結構和狀態機體系
圖4 JAIN-SIP,Resource Adaptor以及SbbEntity之間調用關係
回頁首
三. 事件和事件類型(Events),事件引導(Routing):
1. 事件和事件類型:
在SLEE中和資源適配器中,事件代表外部到達的訊息,向外部傳送的訊息,某些狀態的遷移(例如定時器的時間到),其他的SBB使用Activity Context共享狀態。這就減少了SBB實體間直接對事件的調用,其他的SBB實體可以對事件達到同時處理,這個是和EJB最大的不同的地方。
2. 事件源:
a 外部的協定棧資源(SS7 stacks, SIP stacks,記費系統 ...,Profile觸發)
b SLEE的服務容器內的部件(定時器、服務觸發、數據源觸發)
c 自定義的觸發源(自定義事件)
3.SLEE中的事件描述:
在有多個資源的時候,這些資源所觸發的事件都是放在event-jar.xml和slee-event-jar.xml兩個檔案中的, 而SBB所感興趣的事件,則放在sbb-jar.xml中定義了,以及還包括了一些Sbb需要知道的訊息細節,例如訊息方向,觸發順序和初始化參數:
RegisterEvent
javax.sip.message.Request.REGISTER
javax.sip
1.1
initial-event表示初始事件,也就是事件會觸發實例化一個根Sbb,Root Sbb,就是說這個訊息可能是一個訊息狀態機中的第一個訊息。Root Sbb定義在後續章節會更加詳細的看到。
event-direction表示事件是發出(Fire)還是接收(Receive)來觸發SBB.
event-type-ref這裡表示的相關事件的類型單元,其中event-type-name為事件的名字。
4.SLEE中的事件處理過程:
在SBB中的事件處理句柄是在事件用"On"+ event-name表示,例如在註冊機例子中的RegiterEvent的處理句柄為OnRegisterEvent。
帶入參數:
"on"+( event, activity)
行為實體 activity和 event:
SBB對象作為一個事件消費者通過行為實體了解事件,activity是帶入處理句柄的一個參數,是代表行為實體的接口activity interface,關於行為實體的一些來歷在前面做了介紹。從行為實體接口可以獲得從對端傳送的訊息;從一個Mobicents中的Activity可以獲得一個行為實體的調用--ServerTransaction,
另外一個帶入的參數是這個SBB實體感興趣的訊息,這個訊息是被SLEE自動導入到SBB中去的,這個訊息事件是JAIN-SIP中javax.sip.RequestEvent包的訊息類,從這個類中可以得到SIP訊息的一些具體信息。
圖5 Sbb和活躍實體以及上下文之間的關係圖
回頁首
四.行為實體(Activity)和行為實體上下文(Activity Context)
1.行為(Activity):
在SLEE中對行為如下定義:一個相關事件流的抽象,也是一個根據狀態變化而發出事件的有限狀態機
2. 實體上下文(Activity Context)
SLEE中定義一個ActivityContext是資源實體在SLEE中的表現,SBB實體從ActivityContext中獲得事件,可以把它理解為一個事件匯流排,SBB要獲得事件需要綁定到事件匯流排上去,SBB實體根據它綁定的不同的實體上下文獲得事件觸發相應的動作,並且做出相應的回響動作;而實體上下文接口(ActivityContextInterface)就是也就是SBB對實體訪問的接口,在使用過程當中Sbb一般會根據定義自己的狀態在ActivityContextInterface上增加一個封裝。
3.範例:
下面我們看以下SIP Registrar中實體和實體上下文的例子:
1> 對於一個JAIN-SIP的協定棧實體來說,實體對象是ServerTransaction和ClientTransaction(參看圖5),這兩個交易是針對特定呼叫的,每個呼叫指定一個特定對象。
一個新的SIP呼叫--Register訊息進入SLEE,這個呼叫被某個Sbb所感興趣,
2> SIP呼叫實體傳遞一個SIP的訊息(REGISTER)通過ActivityContext傳遞到SBB實體中去,由onRegisterEvent(RequestEvent event, ActivityContextInterface ac)來進行處理,
3> 從ActivityContextInterface獲得實體ServerTransaction:
ServerTransaction serverTransactionId = (ServerTransaction)ac.getActivity();
4> 從SBB中根據這個狀態機創建一個新的SIP呼叫,並且傳送這個請求:
this.clientTransaction = sipProvider. getNewClientTransaction(request);
clientTransaction.sendRequest();
5> 為了接收這個呼叫中一些訊息的內容,需要綁定當前的SBB實體到ActivityContext接口上,為了將當前SBB行為實體上下文和SIP的行為實體上下文接口結合起來,SLEE規範中提供了一個asSbbActivityContextInterface方法將SIP(或者其他)的行為實體的接口作為參數帶入到SBB的行為實體上下文中,才可以作為提供了一個SBB可以訪問的共享行為實體上下文:
ActivityContextInterface aci=SipActivityContextInterfaceFactory.getActivityContextInterface()
RegistrarActivityContextInterface regACI = asSbbActivityContextInterface(aci)
//以下是對SIP訊息頭的設定,將該特定的SIP訊息和ActivityContextInterface綁定起來,
便於Sbb實體進//行跟蹤,例如針對該訊息的逾時事件,這個在註冊機例子中有詳細的使用過程,
regACI.setSipAddress(sipAddress);
regACI.setSipContactAddress(sipContactAddress);
// callId and cseq used to identify a particular registration
regACI.setCallId(callId);
regACI.setCSeq(cseq);
regACI.attach(getSbbLocalObject());
五.SBB部件和SBB實體
1. SBB實體定義:
1> SBB定義為服務組件,封裝了服務邏輯和相關的觸髮狀態。
2> SBB組件需要包含:
a> Sbb組件產生或者是接收的事件。
b> 單個實例化的狀態:每個實例化域的狀態都被收錄到SLEE集中管理的CMP容器
c> 事件處理句柄: Sbb組件中包含的,每個它所接收到的事件類型的一個事件處理方法。
d> 本地接口:Sbb中定義一個Sbb本地接口,它定義有可能同步被調用的Sbb組件(是在同一個SBB Tree上生成的Sbb才可調用的接口,下面也將詳細介紹)的操作。
e> 子關係成分:SBB成分可能包括零個或者多個子SBB組件
f> 可共享性:SBB組件通過Activity Context的方式與其他SBB組件共享狀態,SBB組件定義。
g> 一個JAVA接口(Activity Context Interface),這個接口定義為了得到和設定這些特性所進行的安全訪問操作。
例子:
在Mobicents中有一個簡單的SIP代理網關範例JainSipProxySbb可以參看,和前面所說的RegistrarSbb做為它的子Sbb,可以通過他們來了解整個Sbb構造。
2. 根SBB和子SBB
a.SBB 實體(Sbb Entity)
SBB實體是SBB組成的一個實例。SBB實體是一個代表著實例持久性狀態的實體。
b.SBB子實體和根SBB實體的定義
在運行時間內,SBB實體可能創造多個SBB子實體。由於SBB實體可能被創造,所以它是一個單一的父目錄。以圖6為例SBB實體子目錄是一個被管理的非循環的樹形表。
圖6詳細說明了父和子Sbb之間的關係,它也顯示了SLEE是所有根SBB實體合理的父親。
在SLEE中定義,在父的SBB訪問子SBB採用"獲得子SBB關係對象"的方法,父的SBB實體使用getSBBLocalObject從SbbContext對象中,獲得一個SBB的本地對象,父SBB實體也將這個本地的SBB對象傳遞到的子SBB中去,例如某些情況下,在子SBB的本地接口中定義一個方法給父SBB用來傳遞訊息到子SBB中去。
下面我們用一個簡單的子SBB的例子來說明這個問題,請參看\Proxy\BaseProxySbb.java 在這裡父 SBB 是 BaseProxySbb 中處理各種 SIP 呼叫的訊息,其中對 Register 事件的訊息是由子 SBB Registera 來進行處理這個 SIP 訊息的,換句話來說,有一個子的 SBB 套用嵌入在父 SBB BaseProxySbb 處理中。
1> 父 Sbb 獲得子 Sbb 的關係:
public void onRegisterEvent(RequestEvent event, ActivityContextInterface ac) {
getDefaultSbbUsageParameterSet().incrementNumberOfRegister(1);
trace(Level.INFO, "Received REGISTER request, class="+event.getClass());
try {
// is local domain?
//在父SBB中了使用了一個方法來創建子的SBB關係,然後並且通過這個子關係創建子SBB的本地對象,這個
//本地對象提供了子SBB可以調用的方法,而且這個子SBB在sbb-jar.xml
中需要對這個獲得子SBB的方法進行
//定義
ChildRelation relation = getRegistrarSbbChild();
… …
2> 子Sbb在sbb-jar.xml中的定義
子SBB在sbb-jar.xml中需要對這個獲得子SBB的方法進行定義:
com.opencloud.slee.services.sip.proxy.JainSipProxySbb
父SBB使用這個方法來創建子SBB實體,
定義了子SBB,這裡表示最後調用的子SBB為RegisteraSbb
RegistrarSbb
定義了獲得子關係的方法名字,調用這個方法可以得到SBB子關係,通過調用子關係可以創建這個子SBB的本地對象
getRegistrarSbbChild
0
…
3> 創建一個子 Sbb 的調用過程:
SBB 的開發者的 SBB 調用方法一般如下,例如對當前 Reigster 事件的 ChildRelation 創建(creat)方法的調用,得到一個新的 SBB 實體,在調用過程中 Registera 的 sbbCreate 將被調用,這裡和一個常見的 SBB 實體創建過程基本相同,返回的是一個以 SbbLocalObject 接口的 SBB 實體:
Public class RegistrarChildRelation implements ChildRelation {
Public sbblocalobject creat() … {
SbblocalObject local=RegisteraSbbLocalObject();
Return local ;}
}
4> 一個套用中的創建並且使用子 SBB 的方法:
調用子關係的創建方法,得到子 SBB 的實體
… …
SbbLocalObject child = relation.create();
//將當前的子SBB綁定到當前的行為實體上下文上去;
// attach child to this activity
ac.attach(child);
//把父實體從當前的上下文上分離出去;
// detach myself
ac.detach(getSbbLocalObject());
// 這樣後續的訊息處理都被重定向到RegisterSbb上去了。
…. …
} catch (Exception e) {
trace(Level.WARNING, "Exception during onRegisterEvent", e);
}
}
從上述例子也可以看到事件優先權的問題,在事件傳送過程中,父SBB實體總是在它的子SBB實體前接收同樣的事件。SBB實體的事件傳遞優先權決定了同級別SBB實體接收事件的順序,另外在SLEE的各個實體關係中,SBB實體的事件傳送優先權可能被改變。
3. 事件傳送優先權
對於實體序列來說。父SBB實體總是在它的子SBB實體前接收同樣的事件。對於優先權的定義大家可以參看規範中的8.5.7部分,要改變優先權的時候會在SbbLocalObject接口的setSbbPriority方法。
4. SBB 實體之間的並行刪除:
SBB實體可以刪除,通過在SbbLocalObject 接口或ChildRelationObject接口調用刪除的方法。當執行刪除時候,SLEE將會刪除SBB的實體和所有SBB父實體後代。
5. SBB 對象
SBB對象是SBB所擴展的抽象類SLEE之一個實例,和SBB實體所不同的是SBB的實體是邏輯的實體,而SBB對象則是一個JAVA的對象,可以被實際調用的。
6. SBB 本地接口和 SBB 本地對象
每個SBB有一個SBB本地接口。SBB的SBB本地接口是一個指定的SBB本地界面,它是由SBB開發者根據SbbLocalObject接口來進行擴展的。
SBB對象通過SbbLocalObject同步地調用目標SBB實體的SBB對象,因此可以理解SbbLocalObject就是一個Sbb對象的實例,這樣使用者可以通過GetSbbLocalObect方法獲得相關的目標對象,並且得到它的調用方法。本質上,SBB本地對象是一個套用SBB本地對象接口和代表目標SBB實體的執行對象。當SBB對象在SbbLocalObject上調用SBB開發者定義的方法時,在Sbb抽象類中的相關方法將被Sbb對象進行調用。另外,Sbb本地對象可以在遠程過程調用的時候作為一個客戶存根對象。本質上來說Sbb的本地接口從提供了對SbbLocalObject的調用能力,通過SbbLocalObject訪問到相對應的SBB實體,這個很有點和EJB的本地接口類似。
7.SBB 的生命對象周期
當 SLEE 採用 newIstance 創建一個 SBB,這個時候 sbb 對象生命周期就開始了,這個時候緩衝Sbb對象,調用setsbbContext將sbbContext(也就是Sbb的上下文)對象傳入Sbb對象中,此時SIP訊息工廠對象或者是地址工廠,以及SIP棧的提供者(SipProvidor)這些的對象的創建都在setSbbContext回調中進行。
當完成了實例化的過程以後,sbb對象將進入對象池,每個Sbb組件都有自己的對象池,例如RegistraSbb對象會進入自己的對象池中,但這個時候Sbb對象還不和任何Sbb實體相關聯。
當一個Sbb接收到一個事件並且開始進程處理過程,而某個業務邏輯調用主動調用這個服務的時候,首先會創建Sbb的實體(sbbEntity)例如在序列圖上看到的EnventRouteImpl這個SLEE這個內部的類就是執行這樣的動作,在EnventRouteImpl中,首先實體暫時不和任何對象相互關聯的,幾個方法可以調用讓Sbb對象將從對象池進入Ready狀態,SbbCreate和SbbActivate,前者是在使用ChildRelation對象中的create的方法或者是事件產生的時候才被調用,後者是一個sbb對象需要調用一個現有的Sbb實體上的某個方法的時候才這樣做,這種情況往往是一個沒有Sbb對象對應一個Sbb實體而進入準備狀態的時候。
對於一個處於Ready狀態的Sbb對象,它已經和具體的某個Sbb實體相關聯了,這個時候Sbb對象可以和Sbb實體之間同步暫態和穩態的數據了,例如一個資料庫之間的同步。需要調用 SbbLaod 方法和SbbStore 方法。SbbLaod方法用資料庫中的數據刷新變數的值,SbbStore方法把變數的值寫入到資料庫中,和EJB的規範一樣,Sbb的開發者,也就是客戶端是不能直接調用SbbLoad 方法和SbbStore 方法。
涉及到具體的業務處理的方法,SLEE要在業務處理方法調用之前調用 SbbLoad 方法刷新數據,業務處理方法執行之後,SLEE 容器又立即調用 SbbStore 方法把數據存儲到資料庫中。,開發人員在業務處理方法中不必刷新和存儲實例變數的值,如果有興趣瀏覽SLEE的原始碼,可以看到,在一個事件到來的階段,一旦一個Sbb實體和某個Sbb對象關聯以後,將調用SbbLoad,而調用刪除或者是Roll Back方法的時候,將調用SbbStore。
刪除對象的方法EJB的生命周期非常相似,這裡就不介紹了。
8.SLEE 如何刪除 SBB 實體子目錄
SLEE用附屬點(attachment count)的機制來刪除SBB實體樹,它不再附屬於任何一個行為實體,它將不再接收事件,也就被刪除了,這個機制也就是JAVA垃圾回收機制的一種擴展。
9. Sbb 的持久穩定狀態:
Sbb採用CMP域(CMP field)定義了它的穩定狀態,CMP將持久保存的管理交給SLEE,SLEE規範中定義的CMP的體系是基本上基於Java EJB2.0規範中,它們之間的不同可以參看規範的6.5章節。
10.服務的定義(service.xml):
在SLEE里被展開的服務展開描述定義一個展開/管理的配置檔案。可以參看Proxy中的service.xml
圖7. 本圖表示了一個外部資源如何將一個訊息轉交給Sbb處理的過程,從圖中可以看到SLEE的端點獲得了事件以後傳遞到核心事件處理系統(Event Routing)中,然後轉交給事件處理的回調過程。
六.數據供應(Provisioned Data)和Profile(數據簡表)
圖8。數據供應的基本組成,從圖上看SBB從Profile Table中得到各個Profile接口,而Profile從Profile Mbean伺服器獲得具體的數據內容,從Profile Management Client的角度上來看,來看是可讀寫的,而從Sbb獲得配置的角度上看,是唯讀的。
1.數據供應(profile):
在SLEE中供應數據表現為闡述數據模型的profile,數據模型將profile集群到profile表中(profile table),Profile中的接口給則定義了應用程式調用的方式,一個Profile的規則包括了接口,類,和部署描述單元,用戶採用這個規則訪問profile,獲得數據信息。
2.關於Profile規格的一些元素和各自的關係:
1> 從Sbb視角上看範例和執行流程;
我們可以下載OpenCloud的Slee的參考設計,描述SBB對profile的調用,在這個Profile中包含了地址簡表和資源簡表兩個對資源描述:
a. 在創建SBB的過程中。sbbCreate中首先通過調用JNDI 的 lookup() 方法執行查找,獲得簡表接口的實例--簡表的工具Profilefacility;
b. 利用Profilefacility簡表工具中的getProfileByIndexedAttribute方法,這個方法是Profile工具中定義的,只要套用了Profilefacility接口就可以使用到這個方法獲得相應的簡表。
帶入的參數中第一個String profileTableName是一個Profile的表名,參數的第二個String attributeName是表中profile,例如在一個表中有address,mail,name這三個Profile,第三個參數就是attributeValue,也就是指具體的特性值,例如某個連線呼叫對應的目的地址值。返回的就是PorfileID也就是每個Porfile的鑑別符。
c. 根據profileid調用getProfile從profile表中獲得profile,我們在上面介紹過一個Profile通過兩個接口繼承,這兩個接口是AddressProfileCMP,和ResourceInfoProfileCMP,SLEE是從Resource Info Profile表的各個接口中獲得資源適配器實體的相關信息,地址簡表在本例中的繼承擴展了另外的一些接口,例如用於對呼叫前轉(Call Forwarding)的地址進行設定或者提取(使用setForwardingAddress和getForwardingAddress的兩個方法來管理)
d. 獲得了profile後就可以調用profile接口中定義好的方法來訪問Profile資源了,例如設定或者獲得呼叫前轉地址。
2> 從管理視角上看Profile的管理過程:
ProfileManagement;一個Profile的管理,對於一個管理客戶端來說,會有一個管理客戶端(Profile Management Client)的接口,這個接口可以被網路管理代理所調用。通過這個接口可以設定或者是獲得Profile的特性,SLEE對Profile管理對象進行實例化的時候,Profile管理對象將會緩衝,而且成為一個實時的運行對象,通過Porfile CMP接口調用持久化域中的設定和獲得的方法(Set/Get)來執行對Profile的訪問,這個和Sbb開發者的使用是一致的。
3> ProfileMbean接口:
Profile規範中規定了採用Profile中的ProfileManagementbean類來提供管理者對Profile的訪問,更確切的說,外部的管理者調用ProfileMbean對象,ProfileMbean對象調用Profile緩衝的ProfileManagement對象,另外要注意的一點是Profile MBean類可以套用在任何JMX規範的MBean類型上,但是必須要在Mbean伺服器上已經註冊的接口才可以(也就是用CreateProfile創建的Mbean,這裡可以把Profile Mbaen理解為JMX Mbean接口的套用)
ProfileMbean的接口可以參看規範156頁的介紹;
七. 服務和部署(Service and Deployment)
總結上面所述我們總結一下基本的服務的部署模式:
和EJB類似,SBB的部署過程是基本相同的,只是服務性質服務描述上不一致,部署描述可以參看EJB的onMessage EJB的部署,部署者這個角色範例在SLEE的部署中同樣有定義,開發者必須實現所有接口的抽象實例,一般這些實例包括:
a. 生命周期內的各個回調方法;
b. 事件(包含某些SLEE內部工具產生的事件,例如TIMER)處理句柄的方法;
c. 傳送訊息,和獲得profile的一些抽象方法等等;
d. 獲得子SBB的方法;
e. 訪問Sbb中CMP域的一些方法;
f. 可共享的數據,例如行為實體等;
在部署服務期間所要定義的的XML檔案和發布方法。
1> META-INF/sbb-jar.xml:sbb的jar檔案,包含了: SBB描述符表示的是SBB的接口,類以及子類的關係,Activity Context的描述,
2> META-INF/event-jar.xml:Mobicents所感興趣的訊息,這裡主要是SIP訊息。 SBB開發者對事件的描述部分,我們在前面已經看到了很多介紹,在部署階段,描述事件類型的Java類檔案就是用該檔案來進行。
3> META-INF/slee-profile-spec-jar.xml:用於對profile的類型進行定義。 在SLEE規範中定義,Profile的jar檔案可以包裝一個或者多個Profile規範。
4> service.xml:定義服務。服務描述檔案是表示所部署的SBB服務的檔案。
5> 部署檔案: deployable-unit.xml:用於對jar執行檔案進行部署,定義事件和定義服務,SBB,資源和profile將裝入SLEE。
6> resource-adaptor-type-jar.xml:用於對資源適配器類型部署的描述。
7> 使用SleeCommandInterface來完成組件的部署任務:
對於部署和套用在Mobicents中,使用了SleeCommandInterface工具,JBOSS主要是使用JMX框架的,各個組件之間採用JMX進行通訊,各個服務組件(Mbean)都以外掛程式的方式掛接在MBean伺服器上,SleeCommandInterface工具中使用了jmx/rmi/RMIAdaptor的Mbean作為服務接口,在下面我們將以創建實體類的方法來介紹一下掛接資源適配器的過程,其他的服務部署和這個也是類似的。
本質上SLeeCommandInterface是一個用於對JAIN SLEE容器在命令行下的部署,啟動服務,創建資源適配器的任務.通常而言,要啟動SLEE容器,要部署和啟動資源適配器,然後是部署和啟動SLEE,關於"SLEE命令"大家可以參看原始碼。
啟動資源適配器是由DeploySipRA.sh來進行,而在範例中啟動網關是由DeploySipProxy.sh來完成.
部署一個SIP資源適配器首先要部署(-deploy)兩個JAR檔案,一個是 sip-ra-type.jar另外一個是sip-local-ra.jar,在創建SIP資源適配器時候,在Mobicents的根目錄下運行ant siptype和ant sipra就可以生成他們,前者包含了SIP事件和Activity的一些定義側重於資源,的後者包含了協定本身的實現
。
下一步是-createRaEntity,也就是創建SIP的資源適配器, resource-adaptor-jar.xml中定義了資源配置器的jar檔案,和resource-adaptor-type-jar.xml不同的地方在於,前者是直接面向特定某個資源配置器的類檔案,例如這裡指明了。
org.mobicents.slee.resource.sip.SipResourceAdaptor
告訴了SLEE資源配置器的調用入口的類,也就是SIP協定的封裝,那么給誰調用呢,回到前面說的createRaEntity創建實體命令來,上面說了通過JMX的框架來完成調用創建的過程,首先在初始化SleeCommandInterface的過程當中,RemoteMbeanServer已經被定義為jmx/rmi/RMIAdaptor,而JNDI中的URL是SBB開發者定義的,在Mobicents中對資源適配器進行管理的是ResourceAdaptorMBean接口,而它的Mobicents中的實例化ResourceAdaptorMBeanImpl繼承了JBOSS中的StandardMBean.這個接口提供了createResourceAdaptorEntity方法來創建資源適配器的實體,這個接口的實例化的過程帶入的參數是當前在resource-adaptor-jar.xml中指定的SIP協定的封裝,並且使用createResourceAdaptorEntity來創建實體SIPRA,實體在SLEE中是以ResourceAdaptorEntity類來表示的,其部署檔案中會調用該類的方法來完成進一步的實施.
最後一步,就是要使用(激活)實體SIPRA了,使用命令-activateRaEntity來進行,和上面的創建實體的過程一樣,同樣是利用ResourceAdaptorMBean接口的來完成的,而方法則是使用了activateResourceAdaptorEntity方法來激活,經過一系列的方法的封裝之後,最後會調用SipResourceAdaptor的start方法,創建偵聽者,訊息工廠,地址工廠的實例。
八.套用範例(SIP代理伺服器,信令網關)
我們下面以SIP代理伺服器(JainSipProxy)為例子來闡述一個基本SIP套用建立的過程:
事件接收:
1. 首先是SLEE接收到一個SIP訊息.
2. 這個事件是一個初始化事件--intial-event
3.如果initial-event-select-variable中規定的事件是 ActivityContext,表示初始化事件帶入的參數,
4. 當資源適配器傳送一個訊息到一個新的活躍實體上下文後,一個對應的服務將會初始化,Event Router可能也會創建一個新的子Sbb來進行處理。
5. 一個活躍實體上下文將會以一對一的方式對應一個事件,也就是Activity。
6. SIP的資源適配器將會把這個活躍實體定義為一個專門的SIP狀態機(SIP Transaction)當中網關維持的SIP會話狀態。
服務邏輯
JAIN SIP協定棧將會接收SIP訊息,事件接收到以後,通過訊息處理器傳送到SLEE的事件引導部分EnventRouteImpl進行,這個時候,Sbb對象將要進入Ready狀態了,調用SbbCreate回調將被調用。
對於初始化的事件來說,initial-event-select表示第一個事件觸發時候將要加入的參數,我們來看這個參數在這裡是Activity Context,也即是JAIN SIP事件傳送到上面去的上下文,這個時候通過EnventRouteImpl選舉到convergence names,你可以理解它為一個事件的回調句柄,也就是事件的消費者,在SBB事件處理回調會調用這個句柄,並且把ActivityContext作為參數帶入。
例如這個時候事件INVITE使用onInviteEvent訊息處理句柄,這個是有狀態的服務,需要代理維持狀態,例如INVITE訊息以及後續的Trying,Ringing,OK等訊息,無狀態的如ACK訊息,有狀態的訊息,意味著要創建一個狀態機維持後續訊息的狀態,也就是ClientTransction和ServerTransction。這兩個狀態機都是維持會話的,而無狀態呼叫,可以訊息序列的最後一個訊息。