1 RPCs
在正常的Netconf/YANG使用情況下,RPCs被用來子產品化Netconf伺服器向Netconf用戶端提供的功能和API。在Controller SAL中,RPCs被用來子產品化Providers提供的功能并提供給Consumers使用。
RPCs用來子產品化可被 使用北向插件的Consumers(應用程式)調用的功能。RPC可以子產品化所有的功能,但通常子產品化不能被抽象成配置資料的功能,如:PacketOut,初始化新會話(控制器-裝置的會話)等。RPC相關的接口和方法實際的定義和使用是在Netconf子產品中。
https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:Southbound_Plugin_Development_Guide#RPCs
1.1 使用方法
RPCs使用rpc語句進行子產品化:
Rpc foo{ } |
這映射到方法
RPC Input
在RPC中插入input語句定義PRC Input。Input結構使用和通知、配置等相同的語句進行定義。
Rpc foo{ input{ .... } } |
RPC Output
使用RPC output語句定義RPC Output(結果的結構)
Rpc foo{ output{ ... } } |
通知
通知用來子產品化來自 向Consumers曝露并被監聽的網絡裝置或南向插件 的事件。Notification用notification語句定義。
notification foo { ... } |
配置資料
Configuration data可以很好的為協定插件和(或)網絡裝置子產品化/提供CRUD通路;或者Configuration data可以作為配置資訊(configuration)向Consumers/applications曝露,子產品化所有功能。使用帶true參數的config語句定義YANG中的Configuration data:
container foo { config true; ... } |
運作時 (隻讀)資料
Runtime(read-only)Data可以很好的為協定插件狀态和(或)網絡裝置進行子產品化/提供讀通路,這種類型的資料可以很好的子產品化資料統計和所有的狀态資料;這些資料都不能被Consumers(應用)修改,但是必要的時候會向外曝露(如:拓撲學習,顯式已連接配接的交換機)。使用帶false的配置子語句(substatement)定義YANG模式中的Runtinme data。
container foo { config false; } |
結構元素
RPCs的結構、通知、配置資料、和運作時資料通過使用元素(資料結構節點)進行子產品化。這種元素定義了通路/存儲這種元素實際的XML結構,DataDom文本和Java APIs。通常這樣定義:
l Container l List l Leaf l leaf-list l choice |
Augumentations
Augumentations通過不同子產品提供的額外的結構擴充元素和語義進行擴充已存在的子產品。Augmentation不能改變原模式中必要(mandatory)節點狀态,也不能引入任何新強制的(mandatory)語句。
2.2 RPC的基本調用過程
l Consumers調用
org.opendaylight.controller.sal.core.api.Broker.ConsumerSession.rpc(QName, CompositeNode)
l Broker發現注冊的RpcImplementation
l Broker調用RpcImplementation.invokeRpc(QName, CompositeNode)
l RpcImplementation處理資料并傳回RpcResult
l Broker将RpcResult傳回給Consumers。
如圖:
對應過程為:
1:Consumer想要與SAL進行通信
2:Consumer進行會話的初始化
3:Consumer調用Broker.ConsumerSession.rpc(QName, CompositeNode)進行注冊
4:Broker為發現注冊的RpcImplementationConsumer建立會話
5:Broker調用RpcImplementation.invokeRpc(QName, CompositeNode)
6:RpcImplementation處理資料并傳回RpcResult
7:Broker将RpcResult傳回給Consumers
1.3 core-api中的RPC
在sal-core-api中與rpc相關的主要是以下幾個檔案:
2.2.1 RpcImplementation.java
這是Providers的RPC實作。為了向其他元件曝露RPC,providers必須為這個接口注冊一個具體實作。
這個接口繼承了Provider接口中的ProviderFunctionality接口;也就是說,RPC的實作就是對Provider功能的封裝,在提供給Consumer(應用)使用。
定義方法invokeRpc(),通過rpc的QName和輸入的節點調用相應的RPC:
ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, CompositeNode input); } |
同時在RoutedRpcDefaultImplementation接口中也聲明了invokeRpc()方法,此方法與上面的方法的不同之處在于後者方法中的參數多一個InstanceIdentifier identifier這是節點執行個體的辨別符(每個節點的執行個體都有一個QName以及Identifier,Indentifier功能目前未知)。但這兩個接口之間不存在繼承關系,方法當然不存在重寫的關系。同時RoutedRpcDefaultImplementation接口中隻聲明了一個invokeRpc()方法。
public interface RoutedRpcDefaultImplementation { ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input); } |
2.2.2 RpcConsumptionRegistry.java
定義了一個RpcConsumerRegistry接口,該接口中隻聲明了一個rpc()方法,如下:
Future<RpcResult<CompositeNode>> rpc(QName rpc, CompositeNode input) |
該方法在Broker接口中的ConsumerSession接口中也聲明了這個方法兩個方法完全一樣。
2.2.3 RpcRegistrationListener.java
全部代碼如下,該接口用于監聽,RPC注冊事件。該接口繼承了java.util.EventListener接口。這是所有事務都必須繼承的接口。
import java.util.EventListener; import org.opendaylight.yangtools.yang.common.QName; public interface RpcRegistrationListener extends EventListener { public void onRpcImplementationAdded(QName name); public void onRpcImplementationRemoved(QName name); } |
2.2.4 RpcRoutingContext.java
定義了一個公共類實作兩個接口
2.2.4.1 實作接口及方法重寫
① 該類實作了Immutable接口,該接口中并未申明方法和變量但是用了@interface注解:
public @interface Immutable {} |
@interface是用來自定義JAVA Annotation的文法,注釋中的每一個方法定義了這個注釋類型的一個元素,注釋中方法的聲明中一定不能包含參數,也不能抛出異 常;方法的傳回值被限制為簡單類型、String、Class、emnus、注釋,和這些類型的數組。方法可以有一個預設值。
② 實作了Serializable接口
通過實作 java.io.Serializable 接口以啟用其序列化功能。可序列化類的所有子類型本身都是可序列化的。序列化接口沒有方法或字段,僅用于辨別可序列化的語義。在反序列化過程中,将使用該類的公用或受保護的無參數構造方法初始化不可序列化類的字段。可序列化的子類必須能夠通路無參數的構造方法。可序列化子類的字段将從該流中還原。
③ 重寫方法toString()
将context和rpc中的内容轉化成RpcRoutingContext [context= context, rpc= rpc ]格式,一般用作測試。
④ 重寫hashCode()方法,這個看不懂
public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((context == null) ? 0 : context.hashCode()); result = prime * result + ((rpc == null) ? 0 : rpc.hashCode()); return result; } |
⑤ 重寫equals()方法,将兩個類進行比較,相同則傳回true,不同傳回false。
2.2.4.2 變量和方法
① 私有構造函數進行初始化;
② 定義私有final成員變量:serialVersionUID;
③ 定義私有方法Create(),傳回值類型為RpcRoutingContext類,調用此函數時根據QName參數建立RpcRoutingContext類的對象 ;
④ 公共方法getContext(),傳回值類型為QName擷取context的QName,因為需要通過BundleContext注冊對外提供的服務,同時也可以通過BundleContext來獲得需要引用的服務;
⑤ 公共方法getRpc(),傳回值類型QName,擷取rpc的QName。
2.2.5 RpcProvisionRegistry.java
為RPC的執行個體提供注冊,通過Broker提供服務,為RPC的實作提供注冊。已注冊的RPC功能可以被所有其他已向Broker注冊的Consumers和Providers通過關聯RPC的QName獲得。addRpcImplementation(),addRpcRegistrationListener(),addRoutedRpcImplementation()這些方法将各種RPC實作進行注冊,并傳回對應類型的RpcResult。
2 QNames
正常的XML QName由本地元素名和XML命名空間組成。為了支援版本變化,添加了子產品版本。
qname是qualified name 的簡寫構成:由名字空間(namespace)字首(prefix)以及冒号(:),還有一個元素名稱構。QName是有着特定格式的xml元素,其作用主要是增加了名字空間,比如有同樣的元素名稱,而名字空間不同的情況。
在YANG模式下,QName用來給定義節點名、類型、程式(procedure)或通知命名。
需要通過BundleContext注冊對外提供的服務,同時也可以通過BundleContext來獲得需要引用的服務;
QName=(XML命名空間,版本号,本地名):
n XML命名空間(XML namespace):YANG模式下定義的元素、類型、過程和通知的命名方式
n 版本(Revision ):YANG子產品中描述元素的版本号
n 本地名:YANG模式中定義節點的辨別符
QName.java中對于QName類的部分定義:
//QName的字首,如QName“a:foo”的字首就是“a” public String prefix; // QName的本地部分.如QName "a:foo"的本地部分就是“foo” public String localpart; //QName的元素名稱,如QName“a:foo”的rawname就是“a:foo” public String rawname; //URL與QName的字首是綁定的,這種綁定必須用XML命名空間感覺處理器來處理 //The URI to which the qname prefix is bound. This binding must be performed by a XML Namespaces aware processor. public String uri; |
疑問:
1、多個QName.class檔案?(RpcImplementation.java)
以上内容純屬個人總結,存在很多的不完善和錯誤,僅作參考和讨論用