00001 #!/usr/bin/env python 00002 # -*- coding: euc-jp -*- 00003 00004 ## 00005 # \file CorbaPort.py 00006 # \brief CorbaPort class 00007 # \date $Date: 2007/09/26 $ 00008 # \author Noriaki Ando <n-ando@aist.go.jp> and Shinji Kurihara 00009 # 00010 # Copyright (C) 2006-2008 00011 # Noriaki Ando 00012 # Task-intelligence Research Group, 00013 # Intelligent Systems Research Institute, 00014 # National Institute of 00015 # Advanced Industrial Science and Technology (AIST), Japan 00016 # All rights reserved. 00017 00018 from omniORB import any 00019 import traceback 00020 import sys 00021 00022 import OpenRTM 00023 import RTC, RTC__POA 00024 00025 00026 00027 ## 00028 # @if jp 00029 # @class CorbaPort 00030 # @brief RT コンポーネント CORBA provider/consumer 用 Port 00031 # 00032 # CorbaPort は RT コンポーネントにおいて、ユーザ定義の CORBA オブジェクト 00033 # サービスおよびコンシューマを提供する Port 実装である。 00034 # <p> 00035 # RT コンポーネントは、Port を介してユーザが定義した CORBA サービスを提供 00036 # することができ、これを RT Service (Provider) と呼ぶ。 00037 # また、他の RT コンポーネントのサービスを利用するための CORBA オブジェクト 00038 # のプレースホルダを提供することができ、これを RT Service Consumer と呼ぶ。 00039 # <p> 00040 # CorbaPort は任意の数の Provider および Consumer を管理することができ、 00041 # Port 同士を接続する際に対応する Provider と Consumer を適切に関連付ける 00042 # ことができる。 00043 # <p> 00044 # CorbaPort は通常以下のように利用される。 00045 # 00046 # <pre> 00047 # # CORBAポートの初期化 00048 # self._myServicePort = OpenRTM.CorbaPort("MyService") 00049 # 00050 # // Provider側 00051 # # この Port が提供する Serivce Provider の初期化 00052 # self._mpros = MyServiceSVC_impl() 00053 # # Service Provider を Port に登録 00054 # self._myServicePort.registerProvider("myservice0", "MyService", self._mpros) 00055 # 00056 # // Consumer側 00057 # # この Port が提供する Serivce Consumer の初期化 00058 # self._mycons = OpenRTM.CorbaConsumer(interfaceType=_GlobalIDL.MyService) 00059 # # Service Consumer を Port に登録 00060 # self._myServicePort.registerConsumer("myservice0", "MyService", self._mycons) 00061 # 00062 # 00063 # # CORBAポートへの登録 00064 # self.registerPort(self._myServicePort) 00065 # 00066 # // connect が行われた後 00067 # self.my_cons._ptr().your_service_function(); // YourService の関数をコール 00068 # 00069 # // connect された 別のコンポーネントにおいて 00070 # self.m_cons1._ptr().my_service_function(); // MyService の関数をコール 00071 # </pre> 00072 # 00073 # このように、提供したい Service Provider を registerProvider() で登録 00074 # することにより、他のコンポーネントから利用可能にし、他方、 00075 # 利用したい Service Consumer を registerConsumer() で登録することにより 00076 # 他のコンポーネントの Service をコンポーネント内で利用可能にすることが 00077 # できる。 00078 # 00079 # @since 0.4.0 00080 # 00081 # @else 00082 # @class CorbaPort 00083 # @brief RT Conponent CORBA service/consumer Port 00084 # 00085 # CorbaPort is an implementation of the Port of RT-Component's that provides 00086 # user-defined CORBA Object Service and Consumer. 00087 # <p> 00088 # RT-Component can provide user-defined CORBA serivces, which is called 00089 # RT-Serivce (Provider), through the Ports. 00090 # RT-Component can also provide place-holder, which is called RT-Serivce 00091 # Consumer, to use other RT-Component's service. 00092 # <p> 00093 # The CorbaPort can manage any number of Providers and Consumers, can 00094 # associate Consumers with correspondent Providers when establishing 00095 # connection among Ports. 00096 # <p> 00097 # Usually, CorbaPort is used like the following. 00098 # 00099 # <pre> 00100 # RTC::CorbaPort m_port0; // declaration of Port 00101 # 00102 # MyService_impl m_mysvc0; // Serivce Provider that is provided by the Port 00103 # RTC::CorbaConsumer<YourService> m_cons0; // Consumer of the Port 00104 # 00105 # // register Service Provider to the Port 00106 # m_port0.registerProvider("MyService0", "Generic", m_mysvc0); 00107 # // register Service Consumer to the Port 00108 # m_port0.registerConsumer("YourService0", "Generic", m_cons0 ); 00109 # 00110 # // after connect established 00111 # 00112 # m_cons0->your_service_function(); // call a YourService's function 00113 # 00114 # // in another component that is connected with the Port 00115 # m_cons1->my_service_function(); // call a MyService's function 00116 # </pre> 00117 # 00118 # Registering Service Provider by registerProvider(), it can be used from 00119 # other RT-Components. 00120 # Registering Service Consumer by registerConsumer(), other RT-Component's 00121 # services can be used through the consumer object. 00122 # 00123 # @since 0.4.0 00124 # 00125 # @endif 00126 class CorbaPort(OpenRTM.PortBase): 00127 """ 00128 """ 00129 00130 00131 00132 ## 00133 # @if jp 00134 # @brief コンストラクタ 00135 # 00136 # @param self 00137 # @param name Port の名前 00138 # 00139 # @else 00140 # 00141 # @brief Constructor 00142 # 00143 # @param name The name of Port 00144 # 00145 # @endif 00146 def __init__(self, name): 00147 OpenRTM.PortBase.__init__(self, name) 00148 self.addProperty("port.port_type", "CorbaPort") 00149 self._providers = [] 00150 self._consumers = [] 00151 00152 00153 ## 00154 # @if jp 00155 # 00156 # @brief Provider を登録する 00157 # 00158 # この Port において提供したいサーバントをこの Port に対して登録する。 00159 # サーバントは、引数で与えられる instance_name, type_name を、 00160 # サーバント自身のインスタンス名およびタイプ名として、サーバントに 00161 # 関連付けられる。 00162 # 00163 # @param self 00164 # @param instance_name サーバントのインスタンス名 00165 # @param type_name サーバントのタイプ名 00166 # @param provider CORBA サーバント 00167 # 00168 # @return 既に同名の instance_name が登録されていれば false を返す。 00169 # 00170 # @else 00171 # 00172 # @brief Register provider 00173 # 00174 # This operation registers a servant, which is provided in this Port, 00175 # to the Port. The servant is associated with "instance_name" and 00176 # "type_name" as the instance name of the servant and as the type name 00177 # of the servant. 00178 # 00179 # @param self 00180 # @param instance_name Servant instance name 00181 # @param type_name Servant type name 00182 # @param provider CORBA Servant 00183 # 00184 # @return if same instance_name is registered, this will return False 00185 # 00186 # @endif 00187 def registerProvider(self, instance_name, type_name, provider): 00188 if not self.appendInterface(instance_name, type_name, RTC.PROVIDED): 00189 return False 00190 00191 oid = self._default_POA().activate_object(provider) 00192 obj = self._default_POA().id_to_reference(oid) 00193 00194 key = "port" 00195 key = key + "." + str(type_name) + "." + str(instance_name) 00196 00197 OpenRTM.CORBA_SeqUtil.push_back(self._providers, 00198 OpenRTM.NVUtil.newNV(key, obj)) 00199 00200 return True 00201 00202 00203 ## 00204 # @if jp 00205 # 00206 # @brief Consumer を登録する 00207 # 00208 # この Port が要求するサービスのプレースホルダであるコンシューマ 00209 # (Consumer) を登録する。 00210 # Consumer が関連付けられるサービスのインスタンス名およびタイプ名として、 00211 # 引数に instance_name, type_name および Consumer 自身を与えることにより、 00212 # 内部でこれらが関連付けられる。 00213 # Port 間の接続 (connect) 時 には、同一の instance_name, type_name を持つ 00214 # サービスが他の Port から提供 (Provide) されている場合、そのサービスの 00215 # オブジェクト参照が自動的に Consumer にセットされる。 00216 # 00217 # @param self 00218 # @param instance_name Consumer が要求するサービスのインスタンス名 00219 # @param type_name Consumer が要求するサービスのタイプ名 00220 # @param consumer CORBA サービスコンシューマ 00221 # 00222 # @return 既に同名の instance_name が登録されていれば false を返す。 00223 # 00224 # @else 00225 # 00226 # @brief Register consumer 00227 # 00228 # This operation registers a consumer, which requiers a service, 00229 # to the other Port. The consumer is associated with "instance_name" and 00230 # "type_name" as the instance name of the service and as the type name 00231 # of the service that is required. 00232 # 00233 # @param self 00234 # @param instance_name An instance name of the service required 00235 # @param type_name An type name of the service required 00236 # @param consumer CORBA service consumer 00237 # 00238 # @return False would be returned if the same instance_name is registered 00239 # 00240 # @endif 00241 def registerConsumer(self, instance_name, type_name, consumer): 00242 if not self.appendInterface(instance_name, type_name, RTC.REQUIRED): 00243 return False 00244 00245 cons = self.Consumer(instance_name, type_name, consumer) 00246 self._consumers.append(cons) 00247 00248 return True 00249 00250 00251 ## 00252 # @if jp 00253 # 00254 # @brief Interface 情報を公開する 00255 # 00256 # この Portが所有する Provider に関する情報を ConnectorProfile::properties 00257 # に代入する。 00258 # 代入する情報は、NVListの name と value として以下のものが格納される。 00259 # 00260 # - port.<type_name>.<instance_name>: <CORBA::Object_ptr> 00261 # 00262 # ここで、 00263 # - <type_name>: PortInterfaceProfile::type_name 00264 # - <instance_name>: PortInterfaceProfile::instance_name<br> 00265 # である。<br> 00266 # ConnectorProfile::properties では、これらを .(ドット)表記で、 00267 # NameValue のキーとしている。したがって、 00268 # 00269 # <pre> 00270 # PortInterfaceProfile 00271 # { 00272 # instance_name = "PA10_0"; 00273 # type_name = "Manipulator"; 00274 # polarity = PROVIDED; 00275 # } 00276 #</pre> 00277 # 00278 # ならば、 00279 # 00280 # <pre> 00281 # NameValue = { "port.Manipulator.PA10_0": <Object reference> } 00282 # </pre> 00283 # 00284 # といった値が ConnectorProfile::properties に格納され、他のポートに対して 00285 # 伝達される。他の Port でこのインターフェースを使用する Consumer が 00286 # 存在すれば、ConnectorProfile からこのキーからオブジェクトリファレンスを 00287 # 取得し何らかの形で使用される。 00288 # 00289 # @param self 00290 # @param connector_profile コネクタプロファイル 00291 # 00292 # @return ReturnCode_t 型のリターンコード 00293 # 00294 # @else 00295 # 00296 # @brief Publish interface information 00297 # 00298 # @endif 00299 def publishInterfaces(self, connector_profile): 00300 OpenRTM.CORBA_SeqUtil.push_back_list(connector_profile.properties, 00301 self._providers) 00302 return RTC.RTC_OK 00303 00304 00305 ## 00306 # @if jp 00307 # 00308 # @brief Interface に接続する 00309 # 00310 # この Portが所有する Consumer に適合する Provider に関する情報を 00311 # ConnectorProfile::properties から抽出し Consumer にオブジェクト参照 00312 # をセットする。 00313 # 00314 # 今、Consumer が 00315 # <pre> 00316 # PortInterfaceProfile 00317 # { 00318 # instance_name = "PA10_0"; 00319 # type_name = "Manipulator"; 00320 # polarity = REQUIRED; 00321 # } 00322 # </pre> 00323 # として登録されていれば、他の Port の 00324 # <pre> 00325 # PortInterfaceProfile 00326 # { 00327 # instance_name = "PA10_0"; 00328 # type_name = "Manipulator"; 00329 # polarity = PROVIDED; 00330 # } 00331 # </pre> 00332 # として登録されている Serivce Provider のオブジェクト参照を探し、 00333 # Consumer にセットする。 00334 # 実際には、ConnectorProfile::properties に 00335 # <pre> 00336 # NameValue = { "port.Manipulator.PA10_0": <Object reference> } 00337 # </pre> 00338 # として登録されている NameValue を探し、そのオブジェクト参照を 00339 # Consumer にセットする。 00340 # 00341 # @param self 00342 # @param connector_profile コネクタプロファイル 00343 # 00344 # @return ReturnCode_t 型のリターンコード 00345 # 00346 # @else 00347 # 00348 # @brief Subscribe interfaces 00349 # 00350 # @endif 00351 def subscribeInterfaces(self, connector_profile): 00352 nv = connector_profile.properties 00353 OpenRTM.CORBA_SeqUtil.for_each(nv, self.subscribe(self._consumers)) 00354 return RTC.RTC_OK 00355 00356 00357 ## 00358 # @if jp 00359 # 00360 # @brief Interface への接続を解除する 00361 # 00362 # 与えられた ConnectorProfile に関連する Consumer にセットされた 00363 # すべての Object を解放し接続を解除する。 00364 # 00365 # @param self 00366 # @param connector_profile コネクタプロファイル 00367 # 00368 # @else 00369 # 00370 # @brief Unsubscribe interfaces 00371 # 00372 # @endif 00373 def unsubscribeInterfaces(self, connector_profile): 00374 nv = connector_profile.properties 00375 00376 OpenRTM.CORBA_SeqUtil.for_each(nv, self.unsubscribe(self._consumers)) 00377 00378 00379 00380 ## 00381 # @if jp 00382 # @brief Consumer の情報を格納する構造体 00383 # @else 00384 # @brief Consumer inforamtion struct 00385 # @endif 00386 class Consumer: 00387 def __init__(self, _instance_name, _type_name, _cons, _consumer=None): 00388 if _consumer: 00389 self.name = _consumer.name 00390 self.consumer = _consumer.consumer 00391 return 00392 00393 self.name = "port."+str(_type_name)+"."+str(_instance_name) 00394 self.consumer = _cons 00395 00396 00397 00398 ## 00399 # @if jp 00400 # @brief ConnectorProfile と Consuemr の比較をしオブジェクト参照を 00401 # セットするための Functor 00402 # @else 00403 # @brief Subscription mutching functor for Consumer 00404 # @endif 00405 class subscribe: 00406 def __init__(self, cons): 00407 self._cons = cons 00408 self._len = len(cons) 00409 00410 def __call__(self, nv): 00411 for i in range(self._len): 00412 name_ = nv.name 00413 if self._cons[i].name == name_: 00414 try: 00415 obj = any.from_any(nv.value, keep_structs=True) 00416 self._cons[i].consumer.setObject(obj) 00417 except: 00418 traceback.print_exception(*sis.exc_info()) 00419 00420 00421 00422 ## 00423 # @if jp 00424 # @brief Consumer のオブジェクトを解放するための Functor 00425 # @else 00426 # @brief Unsubscription functor for Consumer 00427 # @endif 00428 class unsubscribe: 00429 def __init__(self, cons): 00430 self._cons = cons 00431 00432 def __call__(self, nv): 00433 for i in range(len(self._cons)): 00434 name_ = nv.name 00435 if self._cons[i].name == name_: 00436 self._cons[i].consumer.releaseObject()