[openrtm-commit:00284] r272 - trunk/OpenRTM-aist-docs/Documents/03_DevelopersGuide/01_Basic_RTC_Programming/03_ServciePort
openrtm @ openrtm.org
openrtm @ openrtm.org
2011年 7月 31日 (日) 19:28:09 JST
Author: n-ando
Date: 2011-07-31 19:28:09 +0900 (Sun, 31 Jul 2011)
New Revision: 272
Modified:
trunk/OpenRTM-aist-docs/Documents/03_DevelopersGuide/01_Basic_RTC_Programming/03_ServciePort/03_ServicePort_en.txt
Log:
Service Port implementation tutorial in English has been updated.
Modified: trunk/OpenRTM-aist-docs/Documents/03_DevelopersGuide/01_Basic_RTC_Programming/03_ServciePort/03_ServicePort_en.txt
===================================================================
--- trunk/OpenRTM-aist-docs/Documents/03_DevelopersGuide/01_Basic_RTC_Programming/03_ServciePort/03_ServicePort_en.txt 2011-07-31 10:27:27 UTC (rev 271)
+++ trunk/OpenRTM-aist-docs/Documents/03_DevelopersGuide/01_Basic_RTC_Programming/03_ServciePort/03_ServicePort_en.txt 2011-07-31 10:28:09 UTC (rev 272)
@@ -0,0 +1,1480 @@
+// -*- pukiwiki-edit -*-
+//
+// @brief How to use Service Port Basic
+// @date $Date$
+// @author Noriaki Ando <n-ando at aist.go.jp>
+//
+// Copyright (C) 2011
+// Noriaki Ando
+// Intelligent Systems Research Institute,
+// National Institute of
+// Advanced Industrial Science and Technology (AIST), Japan
+// All rights reserved.
+//
+// $Id$
+//
+//* Service Port (Basic)
+
+#contents
+
+//------------------------------------------------------------
+** What is service port?
+
+// {bgVXeðR|[lgwüÅ\z·é½ßÉÍAR|[lg
+// ÔÌf[^ÊM¾¯ÅÍ\ªÅÍÈAR}hx( é¢ÍÖx)
+// ÌR|[lgÔÊMªKvÉÈÁÄ«Ü·Bá¦ÎA{bgA[ð§
+// ä·é}js
[^R|[lgÌêAèæÌÊuâ¬xÈÇÍAãÊ
+// ÌAvP[VâR|[lg©çf[^|[gÅçêé׫f[^
+// Å·B
+
+When you construct your robot systems according to the component based
+software development, not only data-centric communication but also
+command (or function call) based communication between components is
+necessary. For example, in case of a manipulator component which
+controls robot arm, position or velocity of end-effector should be
+given through data port from application programs of upper layer.
+
+// êûA{bgA[ÌeíÝèAÀWnÌÝèA§äp[^ÌÝèA®
+// ì[hÌÝèAÈÇðf[^|[gÅs¤ÌÍKØÆ;¦¸AIuWFN
+// gwüIÉ¢¦ÎA}js
[^IuWFNgÉεÄA
+// setCoordinationSystem(), setParameter(), setMode(), ÈÇÌÖªpÓ³
+// êÄ¢ÄA±êçÌÖðKvɶÄKØÈ^C~OÅÄÔ̪©RÆ¢
+// ¦Ü·B
+
+On the other hand, according to the object oriented principle,
+coordination settings, control parameters settings, operation mode
+settings and other miscellaneous settings for the robot arm should not
+be performed through data ports . It is natural that these
+functionalities are invoked through certain member functions such as
+setCoordinationSystem(), setParameter() and setMode() of a manipulator
+object as necessary at the right time.
+
+#ref(serviceport_example_en.png,40%,center)
+CENTER: ''An example of service port''
+
+// T[rX|[gͱÌæ¤ÈR}hxÌR|[lgÔÌâèæèð
+// s¤½ßÌdgÝðñµÜ·B
+
+The service port provides a mechanism for a command based (or service
+based) communication between components.
+
+// êÊÉT[rXÆÍA@\IÉÖAÌ éÐÆÜÆÜèÌR}h (ÖA
+// \bhAIy[VÈÇÆàÄÎêÜ·) QÅ èAOpenRTM-aistɨ¢
+// ÄÍA±Ì@\ðñ·é¤ðT[rXvoC_(C^[tF[X)A@\
+// ðp·é¤ðT[rXRV
[}(C^[tF[X)ÆÄÑÜ·B
+
+Generally speaking, a service means a set of commands (it is also
+called as functions, methods or operations) which are functionally
+related each other. In the OpenRTM-aist, entities which provide
+functionality are called a service-provider (interface), and entities
+which require and use other service entities are called a service
+consumer (interface).
+
+// ȨAUMLÌKñɨ¢ÄÍAT[rXvoC_ð Privided Interface,
+// ܽT[rXRV
[}ð Required Interface ÈÇÆÄÑA»ê¼êº}
+// Ìæ¤ÈL (|bv (lollipop) A\Pbg (socket) ) Å\µÜ·B
+// ±êÍAêÊIÈpê¨æÑLq@ÈÌÅo¦Ä¨¢½ûªæ¢Åµå¤BÄ
+// Ô é¢ÍÄÎêéûüÅ¢¦ÎAÄÎêéà̪voC_ (Provided
+// Interface) Å èAÄÔà̪RV
[} (Required Interface) Æ¢¤©
+// ûàÅ«Ü·B
+
+In the UML specifications and its notation rules as well, the service
+provider is called as ''Provided Interface'' and the service consumer
+is called as ''Required Interface'', and they are designated as the
+following notation.
+
+#ref(provider_and_consumer_en.png,40%,center)
+CENTER: ''Service provider and consumer''
+
+- Provided Interface: An entity that is called from others and provides services
+- Required Interface: An entity that calls and uses other's services
+
+// voC_¨æÑRV
[}ðÜÆßÄC^[tF[XܽÍAT[rX
+// C^[tF[XÆÄÑA±êçT[rXC^[tF[XðÂ|[gðT[
+// rX|[gÆÄÑÜ·B
+
+The providers and the consumers are referred to collectively as the
+interfaces or the service interfaces, and the port which has these
+service interfaces is called the service port.
+
+** Service port and interfaces
+
+// T[rXC^[tF[XÆT[rX|[gÌÖWÉ¢ÄڵྵܷB
+
+This section describes the relation between service interfaces and
+service ports in detail.
+
+#ref(component_port_interface_ja.png,40%,center)
+CENTER: ''The component, the port and the interface''
+
+// |[gÆÍR|[lgÉt®µAR|[lgÔÌÚ±Ì[_ÆÈé
+// ªðwµÜ·BR|[lgÔÌÚ±ÆÍAR|[lgÉt®·é|[
+// gÔÅÚ±ÉÖ·é²âªsíêA½ç©ÌÝìp (f[^âR}hÌâ
+// èæè) ªs¦éóÔÉ·é±ÆðÓ¡µÜ·B
+
+The port is an end-point, which belongs to a component, for a
+connection between component. Connecting two components means that
+negotiation between ports of components is done and a certain
+interaction (data-centric or command based) can be performed by it.
+
+// |[g©ÌÍf[^âR}hÌâèæèÉεÄA½Ì@\àñµÜ¹ñB
+// ÀÛÉR}hÌâèæèðs¤ÌÍT[rXC^[tF[X (voC_
+// ÆRV
[}) ÉÈèÜ·BêÊIÉ|[gÉÍ@\IÉÖAÌ éCÓÌ
+// ÌCÓÌûüÌC^[tF[XðtÁ·é±ÆªÅ«Ü·B±êÉæèA
+// R}hÌâèæèðêûü¾¯ÅÈoûüÉ·é±ÆàÅ«Ü·B
+
+The port does not provide any functionality for data or command
+communication. Communication between components is actually performed
+by service interfaces (service providers and consumers.) Generally a
+port can associate functionally related service interfaces of any
+number and any directions. This means that not only oneway
+communication but also bidirectional communication can be performed
+through it.
+
+// RV
[}ÆvoC_ÍA|[gªÚ±³ê½Æ«ÉA éðÉîâ
+// ÄÚ±³êARV
[}©çvoC_Ì@\ðÄÑo·±ÆªÂ\ÉÈè
+// Ü·BRV
[}ÆvoC_ðÚ±·é½ßÉÍA¼ÒÌ''^''ª¯¶A
+// ܽÍÝ·«ª éKvª èÜ·B
+
+A consumer and a provider are connected based on a certain condition,
+and then a consumer is able to call provider's functions. In order to
+connect a consumer and a provider, both ''type'' should be same or
+compatible.
+
+// ¯¶^Å éAÆͯêÌC^[tF[Xè`ð±ÆÅ èAÝ·«ª
+// éÆÍAvoC_ÌC^[tF[XªRV
[}ÌC^[tF[X
+// ÌTuNXÌêÂÅ éA(tÉ¢¦ÎARV
[}ÌC^[tF[Xª
+// voC_ÌC^[tF[XÌX[p[NXÌêÂÅ é)Æ¢¤±ÆÉÈ
+// èÜ·B
+
+The same ''type'' means that both interfaces should have same
+definition, and the compatibility means that the provider's interface
+is one of the sub-classes of consumer's interface. In other words,
+the consumer's interface should be one of the super-classes of the
+provider's interface.
+
+***The service port
+
+// RTR|[lgÍf[^|[g¯lACÓÌÌT[rX|[gð±Æ
+// ªÅ«Ü·BܽAT[rX|[gÉÍACÓÌíÞAÌvoC_ܽÍ
+// RV
[}ðtÁ·é±ÆªÅ«Ü·B
+
+The RT-Component can own any numbers of service ports so that data
+ports are so. Moreover, a service port can own any kinds of and any
+numbers of providers and consumers.
+
+// ȺÍAOpenRTM-aistÌTvR|[lg MyServiceProvider ©ç²
+// µ½|[gÆvoC_Ìo^̽ßÌR[hÅ·B
+
+The following code that is excerpted from MyServiceProvider sample
+code of OpenRTM-aist shows how to register a port and a provider to
+the component.
+
+ RTC::ReturnCode_t MyServiceProvider::onInitialize()
+ {
+ // Set service provider to Ports
+ m_MyServicePort.registerProvider("myservice0", "MyService", m_myservice0);
+
+ // Set CORBA Service Ports
+ addPort(m_MyServicePort);
+
+ return RTC::RTC_OK;
+ }
+
+// m_MyServicePort.registerProvider() ÅvoC_ðT[rX|[gIuWF
+// Ng m_MyServicePort Éo^µÄ¢Ü·Bæ3øªÀÌÅ évoC_I
+// uWFNgÅ·BÉAR|[lgÌt[[NNXÅ é
+// RTObjectNXÌaddPort() ÖÅA|[gðR|[lgÉo^µÄ¢Ü
+// ·B
+
+m_MyServicePort.registerProvider() registers a provider to a service
+port object m_MyServicePort. The third argument is an entity of the
+provider object. And next, it is registered to the component by using
+addPort() function which is RTObject component framework class's
+member function.
+
+// ¯lÉATvR|[lg MyServiceConsumer ©ç²µ½R[hð¦µÜ·B
+
+Same as above, following shows the excerpted code from
+MyServiceConsumer sample component.
+
+ RTC::ReturnCode_t MyServiceConsumer::onInitialize()
+ {
+ // Set service consumers to Ports
+ m_MyServicePort.registerConsumer("myservice0", "MyService", m_myservice0);
+
+ // Set CORBA Service Ports
+ addPort(m_MyServicePort);
+
+ return RTC::RTC_OK;
+ }
+
+// voC_ÌêÆÙÆñǯ¶ÅAm_MyServicePort.registerConsumer() Ö
+// ÅRV
[}ð|[gÉo^µA»Ì|[gð addPort() ÖÅR|[
+// lgÉo^µÄ¢Ü·B
+
+Almost same as the provider's case, m_MyServicePort.registerConsumer()
+function registers a consumer to a port, and the port is registered to
+the component by addPort function.
+
+// ÈãAÁÉà¾àȵÉA»ê¼ê m_myservice0 Æ¢¤IuWFNgªAv
+// oC_AܽÍRV
[}Å éƵÄR[háð¦µÜµ½ªAȺA
+// ±êçÌC^[tF[XªÇÌæ¤Éè`³êAIuWFNgªÇÌæ¤É
+// À³êé©ðྵĢ«Ü·B
+
+An object m_myservice0 assumed a provider and a consumer without any
+explanation and they are used in the codes shown above. How to define
+these interfaces and how to implement these objects are shown in the
+following.
+
+***Interface defintion
+
+// C^[tF[XÆͽŵ天HC++Å êÎA¼zNXðC^[
+// tF[XÆÄñ¾èµÜ·µAJava;êxÅ interface L[[hªp
+// Ó³êĢܷB
+
+What is the interface? In C++ language, pure virtual classes are
+called interface. In Java language, ''interface'' keyword is used for
+interface definition.
+
+// OpenRTM-aistÉÍA¾êâOSÉ˶µÈ¢Albg[N§ßÅ éÆ¢Á½
+// Á¥ª èÜ·ªA±êÍCORBAÆÄÎêéªUIuWFNg~hEGAð
+// p·é±ÆÉæèÀ»³êĢܷBCORBAÍAÛW»cÌOMGÅW»³
+// êÄ¢éªUIuWFNg~hEGAÅAWÉ]ÁÄA½ÌïÐâcÌA
+// ÂlÈǪ½lÈÀðñµÄ¢Ü·B
+
+The main important features of the OpenRTM-aist are language
+independence, OS independence and network transparency, and these
+features are realized by using the distributed object middleware which
+is called the CORBA. The CORBA is one of the distributed object
+middleware which is standardized in a international standardization
+organization OMG (Object Management Group), and a lot of
+implementations compliant to the standard are provided by various
+companies, organizations and individuals.
+
+// OpenRTM-aistÅÍAC^[tF[XÍIDLÆÄÎêéCORBAÌC^[tF[
+// Xè`¾êÉæÁÄè`µÜ·B±ÌIDL;êÉ˶µÈ¢C^[tF[X
+// è`û@ðñµAܽIDLRpCÆÄÎêéX^uâXPgð¶¬c[
+// ðp·é±ÆÅAeí¾êÉε½R[hª©®Iɶ¬³êÜ·BX
+// ^uÆÍA[gÌIuWFNgðÄÑo·½ßÌvLVIuWFNgÌ
+// ½ßÌR[hÅ èAXPgÆÍAvoC_ðÀ·é½ßÌx[XÆ
+// ÈéR[hÅ·B
+
+In the OpenRTM-aist, interfaces are defined by the IDL (Interface
+Definition Language) that is an interface definition language of
+CORBA. The IDL provides a definition scheme independent from any
+languages, and by using IDL compiler which generates stubs and
+skeletons, language dependent codes are automatically generated. The
+stubs include code of proxy objects which call remote objects, and the
+skeletons include base classes to implement providers.
+
+// ±êç©®¶¬³êéR[h̨©°ÅAÙÈé¾ê¯mÌÄÑoµàV[
+// XÉs¤±ÆªÅ«Ü·Bá¦ÎAC++ÅÀ³ê½voC_ðAPythonâ
+// JavaÅeÕÉÄÑo·±ÆªÅ«éÌÅ·B
+
+By the automatically generated codes, the invocation between different
+languages can be performed seamlessly. For example, a provider object
+which is implemented in C++ language can be called from Python and/or
+Java easily.
+
+// ȺÍAOpenRTM-aistÌTvÅgp³êÄ¢éIDLè`Å·B
+
+An IDL definition used in a OpenRTM-aist's sample is shown in the
+following.
+
+ module SimpleService {
+ typedef sequence<string> EchoList;
+ typedef sequence<float> ValueList;
+ interface MyService
+ {
+ string echo(in string msg);
+ EchoList get_echo_history();
+ void set_value(in float value);
+ float get_value();
+ ValueList get_value_history();
+ };
+ };
+
+// module ÆÍ C++ž¤Æ±ë̼OóÔÌæ¤ÈàÌÅA±êÉæèC^[
+// tF[X¼ðAEµÕËðh®±ÆªÅ«Ü·B
+
+The keyword ''module'' is almost same as namespace in C++ language,
+this qualifies the name of the interface and the collision of name can
+be avoided.
+
+// C¾êƯlÉ typedef L[[hª èÜ·BãÌáÅÍAsequence ÆÄ
+// Îêé®Izñ^ðè`µÄ¢Ü·BêÂÍAstring (¶ñ^) ^ÌXg
+// ƵÄAEchoList ^Aà¤ÐÆÂÍ float ^ÌXgÆµÄ ValueList ^ð
+// è`µÄ¢Ü·BÁÉ sequence ^ÍAtypedef ¹¸ÉAè`żÚg¤±
+// ƪūȢÌÅA±Ìæ¤É\ß typedef µÄ¨Kvª èÜ·B
+
+You can use ''typedef'' keyword as same as C language. An array type
+called ''sequence'' is defined in the above example. A EchoList type
+as string list type and a ValueList type as float list type are
+defined. Especially, since you cannot use sequence types directly,
+the sequence type should be defined by using typedef before it is
+used.
+
+// É interface ÅnÜ骪ÀÛÌC^[tF[XÌè`ÉÈèÜ·B
+// MyService C^[tF[XÉÍA5ÂÌÖ (IDLÅÍIy[VÆÄÑ
+// Ü·) ªè`³êĢܷBÙÆñÇÍAC¾êâJavaÈÇƯ¶æ¤Èè`Å
+// ·ªAIDLÅÍøªüÍÅ é©oÍÅ é©ð¾mÉ·é½ßÉAøé¾
+// ÌOÉA''in'', ''out'' Ü½Í ''inout'' ÌCüqªt«Ü·B
+
+Next, the part which starts with ''interface'' keyword is the actual
+interface definition. The MyService interface owns five functions (in
+IDL they are called ''operations'') in it. Syntax is almost same as C
+language and Java language, but one of the specifiers ''in'', ''out''
+or ''inout'' is put before each argument to specify whether the
+argument is used as input, output or both.
+
+***IDL compilation
+
+// }ÉAIDLè`©çIDLRpCAvoC_ÌÀ¨æÑX^uÌp̬
+// êð¦µÜ·B
+
+The following figure shows the flow of IDL definition, IDL
+compilation, implementation of provider and use of stub.
+
+#ref(idlcompile_stub_skel_ja.png,40%,center)
+CENTER: ''IDL compilation and stub and skeleton''
+
+// è`³ê½IDLðIDLRpCÉ^¦ÄRpCðs¤ÆAÊíX^uÆX
+// Pg (ܽÍT[oÆNCAgÆ¢¤ÄÑûð·éêà é) ̽
+// ßÌR[hª¶¬³êÜ·B
+
+Giving defined IDL to a IDL compiler and compiling it, stubs and
+skeletons (these are sometimes called servers and clients) are
+generated.
+
+// NCAgA·Èí¿T[rXðp·é¤ÍAX^uR[hðCN[
+// h·éÈǵÄAX^uƵĢè`³êÄ¢évLV(ã)IuWFNg
+// ðpµÄA[gÉ éAT[oÌ@\ÉANZXµÜ·BȺÉC++ÅÌ
+// R[háð¦µÜ·B
+
+A client, which is using service, accesses to the functions of server
+on a remote node through proxy object defined as stub that is included
+in the stub code. An example in C++ language is shown in the
+following code.
+
+ MyService_var mysvobj = <something to get remote object reference>
+ Retval retval = mysvobj->myoperation(argument);
+
+// MyService_var Æ¢¤ÌªAvLVIuWFNg̽ßÌé¾Å·B
+// mysvobjÉ[gIuWFNgÌQÆð½ç©Ì`Åãü·éÆA»ÌºÅs
+// íêÄ¢é myoperation() ÖÌÄÑoµÍAÀÛÉÍ[gɶݷéI
+// uWFNgɨ¢ÄsíêÜ·B±ÌMyService_var NXªè`³êÄ¢é
+// ̪X^uÉ ½èÜ·B
+
+A line starting with MyService_var is declaration for a proxy object.
+After substituting a remote object reference into the ''mysvobj''
+variable, the invocation of myoperation() function performs remote
+object function call actually. The MyService_var class is the stub
+defined in the stub code.
+
+// êûAãLÌû@ÉæÁÄÀÛÉÄÎêéT[o¤ÌIuWFNgÍAȺÌ
+// æ¤ÉXPgNXðp³µÄȺÌæ¤ÉÀ³êÜ·B
+
+On the other hand, the server side object which is called by the above
+method is implemented by inheriting a skeleton class as follows.
+
+ class MyServiceSVC_impl
+ : public virtual MyService,
+ public virtual PortableServer::RefCountServantBase
+ {
+ public:
+ MyServiceSVC_impl() {};
+ virtual ~MyServiceSVC_impl() {};
+ Retval myoperation(ArgType argument)
+ {
+ return do_ something(argument);
+ }
+ };
+
+// ³çÉA±±Åè`³ê½T[ogNXðCX^X»µACORBAIuWF
+// NgƵÄANeBx[g·é±ÆÅA[g©çIy[VðÄÑo
+// ·±ÆªÅ«Ü·B
+
+And, instantiating a servant class defined above, and activating it as
+a CORBA object, operations can be called from remote node.
+
+ // some spells to startup ORB of CORBA
+ MyServiceSVC_impl mysvc;
+ POA->activate_object(id, mysvc);
+
+// IDLðè`µÄARpC·é±ÆÅAªUIuWFNgðè`µp·éÌ
+// ÉKvÈå¼ÌR[hª©®Iɶ¬³êÜ·B½¾µAãLÌu½ç©Ìû
+// @Å[gIuWFNgÌQÆðæ¾vµ½èAuCORBAÌORBðN®·é½
+// ßÌ¢ë¢ëȨܶȢvÆ¢Á½àÌÍACORBAð¼Úp·éêÉÍË
+// RƵÄR[fBO·éKvª éªÅ èA±êçÍCORBAðp·é¤
+// ¦Åàðªïµ©Á½èAÏGÈìƪKvÆÈéªÅ·B
+
+Defining and compiling IDL, most of codes required to define and use
+distributed objects are generated automatically. However, ''something
+to get remote object reference'' and ''some spells to startup ORB of
+CORBA'' are still required in the actual coding, and these are one of
+difficult and complicated things in use of CORBA.
+
+// µ©µÈªçAOpenRTM-aistðp·êÎA±¤µ½CORBAÌlXÈÄÑoµÌ
+// å¼ÍBÁ³êAÀÒÍNCAgÌÄÑoµAT[ogÌÀÉÌÝ
+// W·é±ÆªÅ«Ü·BȺÅÍAT[ogðÀµvoC_ƵÄR
+// |[lgÉo^·éû@ARV
[}ƵÄvoC_ðp·éû@
+// É¢ÄÚµ©Ä¢«Ü·B
+
+Using OpenRTM-aist, however, most of these CORBA's native function
+calls are hidden, and developers can concentrate only to servants'
+implementation, and calling servers from clients. In the following,
+how to implement servants and register it to the component and how to
+use providers from the consumers are described in details.
+
+** Implementation
+
+// T[rX|[gÌÀɽÁÄÍARTCBuilderðp·é̪ÖÅ·B©
+// ªÅT[rX|[gAvoC_¨æÑRV
[}ðÀ·é±ÆàÅ«Ü
+// ·ªACORBAâIDLRpCɸʵĢéKvª èÜ·µAMakefileâR[
+// hÌlXȪ𫷦éKvª èÜ·ÌÅ Ü訩ßūܹñB
+
+It is convenient to use RTCBuilder in implementing a service port.
+You can implement service ports, providers and consumers by yourself.
+But a detailed knowledge of CORBA, IDL compiler is required, and
+Makefile and some parts of source code have to be modified. It is not
+recommended.
+
+// RTCBuilderÌÚ×Èg¢ûÍARTCBuilderÌ}j
AðQƵľ³¢B
+
+See the manual of RTCBuilder for the detailed usage of RTCBuilder.
+
+*** IDL Definition
+
+// T[rX|[gðp·éÉÍAp·éC^[tF[Xð\ßIDLÅè`·
+// é©Aù¶ÌIDLt@CðKÈfBNgÉzuµÄ¨Kvª èÜ·B
+
+In order to use service ports, you have to define interfaces in IDL
+files or use pre-defined IDL files, and have to put them into
+appropriate directory.
+
+// IDLÌè`û@É¢ÄÍA±±ÅÍÚ×Íq×ܹñªA¨¨æ»ÈºÌæ¤
+// ÈtH[}bgÅè`·é±ÆªÅ«AC¾êâJavaɵê½ÇÒÅ êÎAä
+// rIeÕÉè`Å«éŵå¤B
+
+Detailed IDL definition rules are not described here, but it can be
+defined roughly as follows. Developers who are familiar with C or
+Java languages would easily understand it.
+
+ // Module can be defined for namespace.
+ // Using a module definition positively is recommended.
+ module <module name>
+ {
+ // struct could be defined as follows
+ struct MyStruct // structure name
+ {
+ short x; // only short and long integer types are available
+ short y;
+ long a;
+ long b;
+ double dval; // only float and double floating point types are available
+ float fval;
+ string strval; // string type is available for character string
+ };
+
+ // dynamic sequence type should be typedefed previously
+ typedef sequence<double> DvalueList;
+ typedef sequence<MyStruct> MyStructList; // sequence of any struct allowed
+
+ // interface definition
+ interface MyInterface // interface name
+ {
+ void op1(); // no return value, not arguments
+
+ // NG: the following definition is error, because uppercase and lowercase are not distinguished
+ // short op2(in MuStruct mystruct);
+ short op2(in MyStruct mydata); // direction is specified {in, out, inout}
+
+ oneway void op3(); // oneway keyword can be used for only operations with no return
+
+ void op4(in short inshort, out short outshort, inout short ioshort);
+
+ void op5(MyInterface myif); // MyInterface itself can be used for arguments
+ };
+
+ // one or more interfaces can be defined one IDL file
+ interface YourInterface
+ {
+ void op1();
+ };
+ };
+
+
+*** Designing by using RTCBuilder
+
+// ãÌæ¤ÉIDLÅè`µ½C^[tF[XðA±ê©çJ·éRTR|[l
+// gÌT[rX|[gÌvoC_AàµÍRV
[}ƵÄp¢é½ß
+// ÉÍAR|[lgÌR[hWFl[^Å é RTCBuilder ÅT[rX|[
+// gðÝvµA»ÌÛɱÌIDLè`ð^¦ÄâéKvª èÜ·B
+
+In order to use interfaces defined as mentioned above for service
+ports' providers and consumers in your new RT-Component, IDL
+definition should be given to RTCBuilder tool which can be used to
+design RT-Components.
+
+// RTCBuilder ÌVKvWFNgð쬵Ap[XyNeBuðJ«Ü·Beí
+// vt@C(R|[lg̼ÌâJeS¼)AKvÈÝèðsÁ½ãA
+// T[rX|[g^uðJÆAÌæ¤Èæʪ»êÜ·B
+
+Create a new project of RTCBuilder and open perspective of RTCBuilder.
+After setting various required profiles including component's name and
+category, open service port's tab, you can see the following editor
+view.
+
+#ref(rtcbuilder_serviceport_tab1_ja.png,40%,center)
+CENTER: ''Service port's design tab.''
+
+// ܸA''Add Port'' {^ðµT[rX|[gðêÂÇÁµÜ·B»¤·é
+// ÆAsv_name Æ¢¤T[rX|[gªêÂÇÁ³êAºÌBuildViewÌR|[
+// lgÌ ÉA¬³È³û`Ì|[gªêÂÇÁ³êÜ·BRTCBuilderÌGfB
+// ^¶Ì|[gXgÌsv_nameðNbN·éÆAE¤É''RT-Component
+// Service Port Profile''ª\¦³êéÌÅA|[g¼ðKȼO (±±ÅÍ
+// ''MyServiceProviderPort'') ÉÏXµÜ·B
+
+At first, click ''Add Port'' button and add a service port to the
+RT-Component. Then a service port named sv_name is added, and a small
+rectangle signifying a port is added on a component's larger rectangle
+in the build view that is usually located below. Click sv_name in
+port list in the left side of the editor, then ''RT-Component Service
+Port Profile'' will appear on the right side. Please modify it to an
+appropriate name (here it is set as ''MyServiceProviderPort'').
+
+#ref(rtcbuilder_serviceport_tab2_ja.png,40%,center)
+CENTER: ''Adding a service port''
+
+// GfB^¶Ì|[gXgÌ MyServiceProviderPort ðNbNµA''Add
+// Interface''{^ðNbN·éÆAMyServiceProviderPort ÉC^[tF[
+// X ''if_name'' ªêÂÇÁ³êÜ·ÌÅAæÙÇƯlÉGfB^¶
+// Ì''if_name''ðNbNµA''RT-Component Service Port Interface
+// Profile''ãÅ''if_name''ðKȼO (±±ÅÍMyServiceProvider) ÉÏX
+// µÜ·BºÌBuildeViewÅÍA³û`Ì|[gÉ|bvªÇÁ³êAv
+// oC_ (Provided Interface) ª|[gÉtÁ³ê½±ÆªoIɪ©èÜ
+// ·B
+
+Click MyServiceProviderPort in the list at the left side of the editor
+and then click ''Add Interface'' button. You will find an interface
+''if_name'' is added under the MyServiceProviderPort. As well as
+former step, click ''if_name'' at the left side of the editor, then
+rename ''if_name'' to an appropriate name (here it is set as
+''Provided Interface'') on the ''RT-Component Service Port Interface
+Profile''.
+
+
+#ref(rtcbuilder_serviceport_tab3_ja.png,40%,center)
+CENTER: ''Adding a service interface (provider)''
+
+// GfB^E¤Ì Interface Profile ÅÍAC^[tF[XÌvt@Cð
+// ÝèµÜ·Bá¦Î''ûü''Ìhbv_EXgÅÍAÎÛÌC^[
+// tF[XªvoC_ (Provided) ©RV
[} (Required) ©ðwèµÜ
+// ·B
+
+You can set interface profile in the Interface Profile pane at the
+right side of the editor. For example, you can specify the target
+interface as a provider (provided interface) or a consumer (required
+interface) in the ''Direction'' drop-down list.
+
+
+#ref(rtcbuilder_direction_ddown_ja.png,100%,center)
+CENTER: ''Setting direction of a service interface''
+
+// ±±ÅÍvoC_ðÇÁµæ¤ÆµÄ¢éÌÅAProvided ÌÜÜɵÜ
+// ·B±ÌÙ©ACX^X¼AϼÈÇàwèÅ«Ü·ªAK{ÅÍ è
+// ܹñBCX^X¼ÍAÚ±ÉvoC_ÆRV
[}ÌCX^
+// X¼ª¯¶ÈçAÎÖWðwèµÈÄà|[gÌÚ±ð©®IÉs¤ê
+// Ép³êÜ·B
+
+Since we are trying to add a provider interface now, keep it
+''Provided.'' Additionally a intance name, a variable name can be
+specified, but thease are not mandatory parameters. The instance name
+is used as a matching key when service ports are connected without
+detailed interface pair settings.
+
+#ref(serviceif_autoconnection_ja.png,40%,center)
+CENTER: ''Instance name of service interface, and automatic pairing.''
+
+// ½¾µACX^X¼ªÙÈÁÄ¢ÄàAÚ±ÉCÓÌC^[tF[X
+// ¯mðڱūéÌÅAüÍÍK{ÅÍ èܹñBܽAϼÍR[hð
+// ¶¬µ½ÛÉvoC_IuWFNgðãü·éϼðwè·é½ßÌÚ
+// Å·ªA±êàC^[tF[X¼©ç©®Iɶ¬³êéÌÅAüÍÍCÓ
+// Å·B
+
+However, the instance name is not a must, because even if instance
+names are different between provider and consumer, you can specify
+interface pairs at connection time. Although the variable name is
+used to specify the name of variable which is substituted by a
+provider object in the generated source code, it is not mandatory
+since these are also generated automatically from interface name.
+
+// ÉIDLÌwèÆAC^[tF[X^Ìwèðs¢Ü·BãÅè`µ½æ¤È
+// IDLðKÈfBNgÉzuµAIDLt@Cwè{bNX¡Ì Browse {
+// ^ðµAÎÛÆÈéIDLðwèµÜ·B·éÆAwè³ê½IDLÅè`³ê
+// ½C^[tF[XªA»ÌºÌC^[tF[X^Ìhbv_EXg
+// É»êÜ·B±Ìhbv_EXgÅA±Ì|[gÉtÁµ½C^[
+// tF[X¼ðIðµÜ·BIDLt@Cɶ@G[ÈǪ éêÉÍAhb
+// v_EXgÉó]·éC^[tF[Xª»êܹñBÄxIDLt@CÌ
+// è`ð`FbNµÄ¾³¢B
+
+Next, specify interface type and its IDL (Interface Definition
+Language) file. Put IDL files to proper location, and click
+''Browse'' button at the side of IDL file name input form, and specify
+the IDL from the dialogue window. After that, the interfaces defined
+in the IDL file will appear in the interface type dropdown list.
+Select interface to be owned by the port from the dropdown list. If
+IDL file includes some errors such as syntax error, expected interface
+names might not appear. In such case, please check the specified IDL
+file again.
+
+
+
+#ref(rtcbuilder_interfacetype_ddwon_ja.png,100%,center)
+CENTER: ''Selecting interface type''
+
+// ȨAãqÌ''ûü''hbv_EXgÅ ''Required''ðwè·éÆA±
+// ÌC^[tF[XÍRV
[}ÉÈèÜ·BȺÍÊÌR|[lg
+// ''MyServiceConsumer'' ÌT[rX|[gÆC^[tF[XÌÝèæÊÌá
+// Å·B
+
+Moreover, if the ''Required'' is specified in the ''Direction''
+dropdown list, the interface will be a consumer. The following figure
+shows a service port and interfaces setting page of another
+''MyServiceConsumer'' component.
+
+
+#ref(rtcbuilder_serviceport_tab4_ja.png,40%,center)
+CENTER: ''Adding service interface (consumer)''
+
+// GfB^ºÌ BuildView ɨ¢Ä|[gÉ\PbgªÇÁ³êÄARV
[
+// } (Required interface) ª|[gÉtÁ³ê½±ÆªoIɪ©èÜ·B
+
+Finally you will find visually that consumer (Required interface) is
+added to the port in the BuildView pane under the editor.
+
+// *** voC_ÌÀ
+*** Implementing Provider
+
+// voC_Æ¢¤ÌͶÊèAT[rXðvoCh(ñ)·é½ßÌC
+// ^[tF[XÅ·Bµ½ªÁÄAIDLÅè`µ½C^[tF[XðÂT[
+// rXÌgðÀ·éKvª èÜ·B
+
+The Provider is literally a interface to provide some service.
+Therefore, the service that is the actual functionality of the
+provider interface has to be implemented.
+
+// voC_C^[tF[XðÂR|[lgðRTCBuilderÅÝvµ½ê
+// AR[h¶¬ðs¤ÆAR|[lgÌ\[XÌÐÈ`ÆÆàÉAá¦Î
+// C++ÌêÉÍA<T[rXC^[tF[X¼>SVC_impl.cpp Æ <T[rXC
+// ^[tF[X¼>SVC_impl.h Æ¢¤AvoC_ÌÀR[hÌÐÈ`à¶
+// ¬³êÜ·B
+
+In case of designing a component with service provider interfaces by
+RTCBuilder, for example in C++ language, additional provider's
+implementation source code such as <service interface
+name>SVC_impl.cpp and <service interface name>SVC_impl.h will be
+generated with other component template source code.
+
+#ref(rtcbuilder_svcimpl_cxxsrc_ja.png,100%,center)
+CENTER: ''Service provider implementation files (C++,Python,Java)''
+
+ȺÉAe¾êŶ¬³êévoC_ÌÀÌÐÈ`R[hÌt@C¼ð
+¦µÜ·B
+
+Provider's implementation template code file names for each language are shown in the following.
+
+|>|CENTER: ''Generated template code files'' |
+| ''C++'' | <interface name>SVC_impl.cpp &br; <interface name>SVC_impl.h |
+| ''Python'' | <interface name>_idl_example.py |
+| ''Java'' | <interface name>SVC_impl.java |
+
+
+#ref(rtcbuilder_svcimpl_pysrc_ja.png,100%,center)
+CENTER: ''Implementation file for service provider (Python)''
+
+#ref(rtcbuilder_svcimpl_javasrc_ja.png,100%,center)
+CENTER: ''Implementation file for service provider (Java)''
+
+// ±êçÌÀÌÐÈ`ÉÍAIDLÅè`³ê½C^[tF[XÉ·éN
+// Xª 究ßè`³êĢܷB
+
+A class associated to the interface defined in IDL is already declared
+in these implementation templates.
+
+// ±±ÅÍAC++ÅÌÀû@ðáÉÆèAIDLÅè`³ê½Iy[VÌ¢
+// ©ðÀµÄ¢«Ü·B
+
+Here, as an example, some operations defined in IDL will be
+implemented in C++ language.
+
+
+// ****echo()ÖÌÀ
+****echo() operation implementation
+
+// ͶßÉAecho() oÖð©ÄÝÜ·B
+
+Let's see echo() member function at first.
+
+ /*
+ * Methods corresponding to IDL attributes and operations
+ */
+ char* MyServiceSVC_impl::echo(const char* msg)
+ {
+ // Please insert your code here and remove the following warning pragma
+ #ifndef WIN32
+ #warning "Code missing in function <char* MyServiceSVC_impl::echo(const char* msg)>"
+ #endif
+ return 0;
+ }
+
+// #warning vvZbTfBNeBuª èÜ·ªA±êÍgccÅRpC
+// µ½ÛɱÌÖªÀ³êĢȢ±Æðx·é½ßÌàÌÅ·ÌÅA
+// #ifndef²ÆíµÜ·B
+
+You can find the #warning preprocessor directive. Since an error
+arises at the compile time if this function is not implemented, delete
+them including #ifndef directive.
+
+ char* MyServiceSVC_impl::echo(const char* msg)
+ {
+ return msg;
+ }
+
+// ܽA±ÌÖÍAecho() ÖÌøÉ^¦ç꽶ñðAPÉÄÑoµ¤
+// ÉÔ·¾¯Ì@\ðñ·éƵܷBµ½ªÁÄAȺÌæ¤ÉÀ·êÎ
+// æ¢æ¤Év¦Ü·B
+
+Now we assume that this function echo() just return given string in
+argument to the caller. Therefore, the following implementation seems
+apparently normal.
+
+ char* MyServiceSVC_impl::echo(const char* msg)
+ {
+ return msg;
+ }
+
+// µ©µA±êÍRpCÉG[ÉÈèÜ·Bconst char* ð char* Én
+// µÄ¢é½ßÅ·BܽACORBA ÌIuWFNgÌÀû@ƵÄàÔáÁÄ
+// ¢Ü·BCORBAÅÍAreturn ÅÔ³êéIuWFNgÍAORB (Object
+// Request Broker, [gIuWFNgÌÄÑoµªðiéªACORBAÌR
+// A) ÉæÁÄð̳êéÆ¢¤[ª é½ßÅ·B(returnÉÍIuWF
+// NgÌL ðúü·éAÆྡྷܷB)
+
+However, this will be error when it is compiled. Because the const
+char* variable is returned to char* type. Addingly it is also
+incorrect in the CORBA implementation rules. Because CORBA has a rule
+that the ownership of the returned object has to be released and ORB
+destructs after that.
+
+// µ½ªÁÄAreturn ÉÍAÊrÌæðmÛµAmsg ÌàeðRs[µ½¶ñ
+// ðÔ·Kvª èÜ·B±êÉ]¦ÎAȺÌæ¤ÉÀ·êÎæ¢æ¤Év
+// ¤©àµêܹñB
+
+Therefore, in order to return objects, you have to allocate memory and
+copy the contents of msg and return it. According to this rule, the
+following implementation seems correct.
+
+ char* MyServiceSVC_impl::echo(const char* msg)
+ {
+ char* msgcopy;
+ msgcopy = malloc(strlen(msg));
+ strncpy(msgcopy, msg, strlen(msg));
+ return msgcopy;
+ }
+
+// ±±ÅÍAmallocÅÌæðm۵ĢܷªAORBÍfreeÅÌæððÌ·éÌ©A
+// deleteÅðÌ·éÌ©Íí©èܹñBÀÍACORBAÅÍIuWFNg(\¢Ì
+// âzñAܽ»Ì¡^àÜÞ)â¶ñ𵤽ßÌû@ªÊrèßçêÄ
+// ¢ÄA»êÉ]ÁÄÖÌøðó¯æÁ½èAÔµ½è·éKvª éÌÅ
+// ·B
+
+Here, although memory is allocated by using malloc, it is uncertain
+whether the area would be released by free() or delete(). Actually
+CORBA provides methods to allocate and/or destruct objects (including
+structure, array and complex types), and developers have to receive
+argument and return value according to the rules.
+
+// CORBAÅèßçê½û@É]¤ÆAecho()ÖÍȺÌæ¤ÉÀ·éKv
+// ª èÜ·B
+
+According to the CORBA rule, the echo() function should be implemented
+as follows.
+
+ char* MyServiceSVC_impl::echo(const char* msg)
+ {
+ CORBA::String_var msgcopy = CORBA::string_dup(msg);
+ return msgcopy._retn();
+ }
+
+// ÖàÌ1sÚÅÍACORBA̶ñNXCORBA::String ÌX}[g|C^
+// Å é CORBA::String_var ^ð龵ĢܷBString_var ^Í¢íäé
+// L ðÇ·é½ßÌX}[g|C^ÅSTLÌauto_ptrÉĢܷB
+
+In the first line of the function, CORBA::String_var which is a kind
+of smart pointer for CORBA's string class CORBA::String is declared.
+String_var, which is similar to auto_ptr of STL, is a smart pointer to
+manage ownership of objects.
+
+ CORBA::String_var msgcopy = CORBA::string_dup(msg);
+
+// ±Ì String_var ^ÌÏ msgcopy ÉøÌ msg Éi[³êÄ¢é¶ñð
+// Rs[µÄ¢é̪ CORBA::string_dup() ÖÅ·B±ÌÖÅÍøÉ^¦
+// ç꽶ñði[·éÌÉ\ªÈÌæðmÛµA»ÌÌæÉø̶
+// ñðRs[µÄ¢Ü·B
+
+This CORBA::string_dup() function copies the character string stored
+in msg variable to the variable msgcopy which is a String_var type
+variable. In this function, sufficient memory space for given
+characters are allocated and these are copied to the area.
+
+// ÌsÅÍAreturn ÅÄÑoµ³É msgcopy à̶ñðÔµÂÂAIuWF
+// NgÌL ðúüAreturn ¤ÉL ðÚ÷µÄ¢Ü·Bº}ɦ·æ¤É
+// ORB ÅÍAreturn ÅԳ꽶ñðAlbg[NãÌÄÑoµ³ÉMµ
+// Ä©çA¶ñIuWFNgððúµÜ·B
+
+At the next line, character string in msgcopy is returned to caller
+and its ownership is released and is transferred to caller. As shown
+in the following figure, ORB destructs string object after it is
+transferred to the caller on the network.
+
+
+#ref(serviceport_orb_and_provider_ja.png,50%,center)
+CENTER: ''Relation among ORB, operation call and memory management.''
+
+// ±Ì[ðæð·éÆAmsgcopy IuWFNgª echo() ÖàÅgp
+// ³êĢȢ±Æ©çAecho() ÖÌÀÍÅIIÉÍȺÌæ¤Éà±
+// ÆàÅ«Ü·B
+
+According to this rule, since msgcopy object is used only for return
+value in the function, the implementation of the echo() function can
+be written as follows.
+
+ char* MyServiceSVC_impl::echo(const char* msg)
+ {
+ return CORBA::string_dup(msg);
+ }
+
+// CORBA::string_dup() ÖŶñÌæÌmÛÆàeÌRs[ðsÁ½¤¦ÅA
+// »ÌL ð¼ÉÄÑoµ³É^¦Ä¢é±ÆÉÈèÜ·B
+
+This means that CORBA::string_dup() function allocates memory for
+string characters, copies it to there and transfers its ownership to
+caller.
+
+// ±Ìæ¤ÉAT[rXvoC_Í CORBA ÌIuWFNgÅ·ÌÅA»ÌÀ
+// û@ÍÊíÌ C++ ÌÀÆ͵áÁ½âèûÅs¤Kvª èÜ·BÁÉAÖ
+// Ìø¨æÑÔèlÌó¯nµK¥ÍAµ¡GÈæ¤É©¦Ü·B½¾µA
+// ãLÌæ¤ÉAIuWFNgÌL Æ¢¤l¦ûðOªÉ¨¢Äl¦éÆA
+// øðÇÌæ¤Éó¯æé׫ÈÌ©A é¢ÍÔèlðÇÌæ¤ÉԷ׫
+// ÈÌ©ª©¸Æ¾ç©ÉÈèÜ·BÚ×É¢ÄÍAAppendixâ¼ÌCORBAÌQ
+// lðQlɵľ³¢B
+
+In this manner, since a service provider is a CORBA object, its
+implementation have to be performed as a little different way from the
+normal C++ style programming. Especially the rule for argument and
+return value for operations seems difficult to understand. However,
+as mentioned above, if you are keeping the ownership handling of
+objects in your mind, you can easily understand how to receive
+arguments and how to return object. For details, please refer to the
+reference book of Appendix or other CORBA etc.
+
+// ****set_value(), get_value() Æ get_value_history()
+****set_value(), get_value() and get_value_history()
+
+// ÍAset_value() Ö, get_value() Ö¨æÑ get_value_list() Öð
+// ¯ÉÀµÄ¢«Ü·B±êçÌÖÍAset_value() ÅÝè³ê½float^
+// ÌlðÛ¶µÄ¨«Aget_value()Å»ÌlðÔ·Æ¢¤PÈàÌÅ·BܽA
+// get_value_history() ÅÍA¡ÜÅÉZbg³ê½lÌððÛ¶µÄ¨«A
+// ððXgƵÄÔ·Æ¢¤àÌÅ·B
+
+Next, set_value(), get_value() and get_value_list() functions will be
+implemented simultaneously. These functions work as follows.
+set_value() sets a float type value and stores a variable, get_value()
+returns the stored value, and get_value_history() returns history list
+which is recorded past set values.
+
+// ]ܸAlðÛ¶µÄ¨ÏðpӵܷB»ÝÌlÍMyServiceSVC_implN
+// ]XÉCORBA::Float^Ìprivateo[ƵÄpӵܷBêûA
+// ]get_value_history() ÅÍAßèlÉSimpleService::ValueList Æ¢¤CORBA
+// ]ÌV[PX^ªgíêÄ¢éÌÅA±êðo[ÏƵÄÂæ¤Éµ
+// ]Ü·B±êçÌÏé¾ð MyServiceSVC_impl.h Ì MyServiceSVC_impl N
+// ]Xè`ÌÅãÌûÉȺÌæ¤ÉÇÁµÜ·B
+
+At first, a variable to store current value is needed. The current
+value is declared as a CORBA::Float type private member of
+MyServiceSVC_impl class. On the other hand, in the
+get_value_history() function, since a CORBA sequence type
+SimpleService::ValueList is used for return value, same type variable
+should be owned as a member variable. These variable declarations are
+added to the end of MyServiceSVC_impl class definition in
+MyServiceSVC_impl.h.
+
+ class MyServiceSVC_impl
+ : public virtual POA_SimpleService::MyService,
+ public virtual PortableServer::RefCountServantBase
+ {
+ : (*snip*)
+ private:
+ CORBA::Float m_value; // add this line
+ SimpleService::ValueList m_valueList; // add this line
+ };
+
+// ÏÌú»àYê¸És¢Ü·BMyServiceSVC_impl.cpp ÌRXgN^
+// ÅAm_value Í 0.0ÉAm_valueList Í·³0Éú»µÄ¨«Ü·B
+
+Remember to initialize variable. In the constructor in
+MyServiceSVC_impl.cpp, m_value is set to 0.0 and the length of
+m_valueList is set to 0.
+
+ MyServiceSVC_impl::MyServiceSVC_impl()
+ : m_value(0.0), m_valueList(0)
+ {
+ // Please add extra constructor code here.
+ }
+
+// ÉAset_value() ÖðÀµÜ·BøÉ^¦çê½lðoÏ
+// m_value Éãü·éÆÆàÉAm_valueListÉàÇÁµÜ·BCORBAÌV[P
+// X^ÍA®Izñ^ÅA[]Iy[^ÆÆàÉAlength(),
+// length(CORBA::ULong) ÌÖðp·é±ÆªÅ«Ü·Blength() ÖÍA»
+// ÝÌzñÌ·³ðÔµAlength(CORBA::ULong) ÖÍ»ÝÌzñÌ·³ðÝè
+// µÜ·BÀÍȺÌæ¤ÉÈèÜ·B
+
+Next, set_value() function is implemented. Set a value from the
+argument to a member variable m_value, and add it also to m_valueList.
+CORBA's sequence type is a kind of dynamic array type, and [] (array)
+operator, length() and length(CORBA::ULong) operators are
+available. length() returns current length of the array, and
+lenght(CORBA::ULong) set length of the array. The function can be
+implemented as follows.
+
+ void MyServiceSVC_impl::set_value(CORBA::Float value)
+ throw (CORBA::SystemException)
+ {
+ m_value = value; // »Ýl
+
+ CORBA::ULong len(m_valueList.length()); // Getting length of the array
+ m_valueList.length(len + 1); // Increment length of the array
+ m_valueList[len] = value; // Adding a value to the end of the array
+
+ return;
+ }
+
+// echo() ÖÆÍÙÈèACORBA::Long ^ÍC++Ìlong intÆ¿ÅAIuWF
+// NgÌL AÌæmÛâpüÍl¦éKvÍ èܹñBµ½ªÁÄAã
+// Ìæ¤ÉPÈãüÅ\¢Ü¹ñBܽAzñ^ÍA2íÞÌ length() ÖÆ
+// []Iy[^ðpµÄAzñÌ·³ð1ÂâµÄÅãöÉøÌlðãüµ
+// ĢܷBȨAOpenRTM-aistÅÍACORBAÌV[PX^ðSTLÌvectorÉß
+// ¢`Åp·é½ßÌÖev[gðñµÄ¨èA»êðg¤ÆA
+
+Differing from the argument of the echo() function, since CORBA::Long
+type is equivalent of long int type, you do not need to consider
+ownership, allocation and destruction of objects. Therefore, simple
+assignment above is allowed. By using two types of length() function
+and [] array operator of the sequence type variable, length of the
+variable is incremented and a value is added to the tail of the array.
+OpenRTM-aist provides some function templates which enables CORBA
+sequence type to be used like STL vector container, and the above code
+can be implemented as follows.
+
+ void MyServiceSVC_impl::set_value(CORBA::Float value)
+ throw (CORBA::SystemException)
+ {
+ m_value = value; // Current value
+ CORBA_SeqUitl::push_back(m_valueList, value);
+
+ return;
+ }
+
+// Ìæ¤É±ÆªÅ«Ü·BCORBA_SeqUtil.h ÅÍA for_each(), find(),
+// push_back(), insert(), front(), back(), erase(), clear() Æ¢Á½Öª
+// è`³êĢܷB
+
+In the CORBA_SeqUtil.h, for_each(), find(), push_back(), insert(), front(), back(), erase() and clear() functions are defined.
+
+// get_value() ÍȺÌæ¤ÉÈèÜ·B
+
+get_value() can be implemented as follows.
+
+ CORBA::Float MyServiceSVC_impl::get_value()
+ throw (CORBA::SystemException)
+ {
+ return m_value;
+ }
+
+// Û¶³ê½lð return ÅÄÑoµ³ÉÔ·¾¯Å·B±±ÅàAæÙÇÌ
+// echo() ÌáÆÍÙÈèACORBA::Float ªv~eBu^ÈÌÅL ðl
+// ¶·éKvÍ èܹñB
+
+This function only returns the stored value. Differing from echo()
+function, since CORBA::Float is primitive type, you do not need to
+consider ownership, and so on.
+
+// ÅãÉAget_value_history() ÌÀð©Ä¢«Ü·BlÌðªi[³ê½
+// m_valueListðԹ΢¢¾¯Ìæ¤Év¦Ü·ªAæÙÇÌq×½L ÆÌ
+// æÌðúÌâèª é½ßAȺÌæ¤ÉÀ·éKvª èÜ·B
+
+Finally, let's see an implementation of the get_value_history()
+function. Although it seems simply returning m_valueList is enough,
+ownership, because of the problems about allocation and destruction,
+the implementation should be as follows.
+
+ SimpleService::ValueList* MyServiceSVC_impl::get_value_history()
+ throw (CORBA::SystemException)
+ {
+ SimpleService::ValueList_var vl;
+ vl = new SimpleService::ValueList(m_valueList);
+ return vl._retn();
+ }
+
+// Öà1sÚÅÍAV[PX^IuWFNg̽ßÌX}[g|C^Å éA
+// SimpleService::valueList_var ^ÌÏð龵ĢܷB³çÉÌsÅA
+// ±ÌX}[g|C^ÉεÄARs[RXgN^ðÄÑoµÄ»Ì|C
+// ^ðãüµÄ¢Ü·B±êÉæèAÌæÌmÛÆAlÌRs[ª¯Ésí
+// êÜ·BÅãÉAvl._retn() ÅAvl ªÛµÄ¢éV[PX^ÌIuWF
+// NgÌL ðúüµÄAreturn¤ÉIuWFNgðnµÄ¢Ü·B
+
+At the first line of the function, SimpleService::ValeList_var type
+which is a smart pointer type of sequence object is declared. At the
+next line, calling the copy-constructor, its pointer is assigned to
+the declared smart pointer. It performs allocation of memory and copy
+of the value simultaneously. Finally, vl._retn() releases the
+ownership of the sequence type object owned by vl variable, and object
+is passed as return variable.
+
+// »µÄAvl ÍÖàÅgp³êĢȢÌÅAȺÌæ¤É±ÆàÅ«Ü·B
+
+And, since the variable vl is not used in the function, it can be
+coded as follows.
+
+ SimpleService::ValueList* MyServiceSVC_impl::get_value_history()
+ throw (CORBA::SystemException)
+ {
+ return new SimpleService::ValueList(m_valueList);
+ }
+
+
+// ÈãAvoC_ÌÀÉ¢ÄÝīܵ½ªAvoC_ª¢íäé
+// CORBAIuWFNgÅ éÌÅAgp·é^AÏÌó¯nµÌdûÈÇA
+// CORBAÌ[É]ÁÄÀµÈ¯êÎÈèܹñBͶßÍÏíµ´¶é©
+// àµêܹñªAv~eBu^É¢ÄÍ]ÊèÌÀA¡GÈIuWF
+// NgÉ¢ÄÍÌmÛÆðúªÇ±Åsíêé©AL ÍÇ¿çÉ
+// é©ðð·éÆAÇÌæ¤ÉÀ·é׫ÈÌ©ðÅ«éÆv¢Ü·B
+
+What you just read is the outline of implementation of service ports.
+Since a provider is a kind of CORBA object, they should be implemented
+according to the CORBA way such as types to be used, the way of
+argument passing. Although you might feel it a little troublesome at
+first, you can use primitive types as conventionally, and you can
+easily understand how to use other complex types if you understand
+ownership of variables and memory allocation and destruction.
+
+***Using Consumers
+
+// RV
[}ÅÍAãÅÀµ½T[rXvoC_ðÄÑoµA»Ì@\ð
+// p·é±ÆÉÈèÜ·BRV
[}ðÂR|[lgÌÐÈ`R[h
+// ðRTCBuilderŶ¬µ½êÉÍAvoC_ÌêÆÍÙÈèÁÊÈt@CͶ
+// ¬³êܹñB
+
+Consumers call service providers which are implemented as presented
+above and use their functionality. When RTCBuilder generates template
+source code of component which has consumers, other special files are
+not created, unlike component which has providers.
+
+// »ÌãíèAR|[lgÌwb_ÉȺÌæ¤ÈvoC_Ìv[Xz
+// _Å éRV
[}IuWFNgªé¾³êÜ·B
+
+In stead of generating files, the following consumer object as a place holder will be declared in the header of component source code.
+
+
+ : (*snip*)
+ // Consumer declaration
+ // <rtc-template block="consumer_declare">
+ /*!
+ */
+ RTC::CorbaConsumer<SimpleService::MyService> m_MyServiceConsumer;
+
+ // </rtc-template>
+
+ private:
+ : (*snip*)
+
+// ±êÍARTC::CorbaConsumer NXev[gÉ^ø
+// SimpleService::MyService ð^¦ÄAMyService ^ÌRV
[}ðé¾µÄ
+// ¢é±ÆÉÈèÜ·BܽAÀt@CÌûÅÍAonInitialize() Öɨ
+// ¢ÄARV
[}Ì|[gÖÌo^ÆA|[gÌR|[lgÖÌo^ª
+// síêÄ¢é±ÆªmFÅ«Ü·B
+
+This means that type argument SimpleService::MyService is given to the
+class template of RTC::CorbaConsumer, and MyService type consumer is
+declared. You can find that they are registered to a port in the
+onInitialize() function and the port is also registered to the
+component in the implementation file.
+
+ RTC::ReturnCode_t MyServiceConsumer::onInitialize()
+ {
+ : (*snip*)
+ // Set service consumers to Ports
+ m_MyServiceConsumerPortPort.registerConsumer("MyServiceConsumer",
+ "SimpleService::MyService",
+ m_MyServiceConsumer);
+
+ // Set CORBA Service Ports
+ addPort(m_MyServiceConsumerPortPort);
+ // </rtc-template>
+
+ return RTC::RTC_OK;
+ }
+
+
+// wb_Åé¾³êÄ¢½ m_MyServiceConsumer ϪAregisterConsumer()
+// oÖÉæÁÄ|[gÉo^³êÄ¢é±Æªª©èÜ·Bæ1øÅÍA
+// ±ÌRV
[}ÌuCX^XÏvªAæ2øÅÍRV
[}ÌuC
+// ^[tF[X^vªA»µÄæ3øÅÍRV
[}ÌCX^XÅ é
+// m_MyServiceConsumer Ϫ»ê¼ê^¦çêĢܷB±êÉæÁÄAR
+// V
[}ªCX^X¼A^¼ÆàÉ|[gÉÖAt¯çêÄ¢é±ÆÉÈ
+// èÜ·B
+
+You can see that a variable m_MyServiceConsumer which is declared in
+the header is registered to a port by the registerConsumer() member
+function. An instance variable of the consumer as the first argument,
+an interface type of the consumer as the second argument, and
+m_MyServiceConsumer variable of a instance of the consumer as the
+third argument are given to the function respectively. According to
+this function call, the service consumer is associated with a port
+with instance name and type name.
+
+// RV
[} m_MyServiceConsumer ÍãÅàq×½æ¤ÉAvoC_Ìv[
+// Xz_ÉÈÁĢܷBC++ÅÍAIuWFNgÖÌ|C^Ìæ¤Éµ¤±
+// ƪūܷB
+
+As above mentioned, the consumer m_MyServiceConsumer is a place holder
+of a provider object. In C++ language it can be handled as a pointer.
+
+MyService C^[tF[XÅÍAstring ^ (CORBAÌstring^) øðêÂ
+æé echo() Iy[Vªè`³êĢܵ½Bµ½ªÁÄAá¦ÎȺ
+Ìæ¤É echo() ÖðÄÑo·±ÆªÅ«Ü·B
+
+ m_MyServiceConsumer->echo("Hello World");
+
+// C++ÅÍãÌæ¤É|C^AJavaâPythonÅÍQÆÌæ¤ÉAIy[V
+// ðÄÑo·±ÆªÅ«éÌÅ·B
+
+Operations can be called by it like a pointer in C++ language, and a
+reference in Java and Python languages.
+
+// ³ÄA±±Å¨ÌÇ¢ûÍA|C^ܽÍQÆÌw·æÍêÌǤÈÁÄ¢
+// éñ¾Æ¨v¢Åµå¤BC++ÅàAá¦ÎȺÌæ¤ÈR[hÍ
+// segmentation fault ŦÀÉ¿Ü·B
+
+And now, readers who have enough experience in C++ language might be
+wondering what is the entity of the pointer and the reference. In C++
+language, the following code is aborted immediately by segmentation
+fault.
+
+ class A {
+ public:
+ const char* echo(const char* msg) {
+ std::cout << msg << std::endl;
+ return msg;
+ }
+ };
+
+ int main (void) {
+ A* a;
+ a->echo("Hello World!!");
+ }
+
+// a Ínull|C^Å·ÌÅA½àIuWFNgðwµÄ¢Ü¹ñB±êƯl
+// ÉAãÌ m_MyServiceConsumer àAR|[lgÌN®¼ãÉÍA¢©Èé
+// IuWFNgàwµÄ¢Ü¹ñÌÅARIy[VðÄÑo·±ÆªÅ
+// «Ü¹ñBãÌ class A ÌêÅÍA
+
+The "a" is a null-pointer, and it points nothing. In the same way,
+since m_MyServiceConsumer can be state that does not point any object,
+it cannot call any operations. In the above example, variable "a" can
+be a valid pointer if a new object is created and is assigned to the
+pointer as the following.
+
+ int main (void) {
+ A* a;
+ a = new A();
+ a->echo("Hello World!!");
+ }
+
+// IuWFNgðnewŶ¬µÄAÏ a ÉãüµÄ °êÎ a Í»Ì_Å
+// éIuWFNgðwµ¦·³È|C^Å·ÌÅAclass AÌoÖÅ
+// é echo() ðÄԱƪūܷB
+
+Therefore, now variable "a" can call the "echo()" function which is a
+member of class A.
+
+// µ©µÈªçAR|[lgÈ¢ÌRV
[}ªÄÑoµ½¢ÌÍAlb
+// g[NãÌDZ©É éIuWFNgÌIy[VÅ·Bµ½ªÁÄA
+// m_MyServiceConsumer ªwµ¦·ÌÍ[gIuWFNgÌQÆ (CORBAIu
+// WFNgQÆ(t@X)) Å·B
+
+However, consumer in the component would call a operation of the
+remote object which is located somewhere on the network. In other
+words, m_MyServiceConsumer points a reference (CORBA's object
+reference) to a remote object.
+
+// Àͺ}ɦ·æ¤ÉARV
[}Í»Ì|[gªvoC_ðÂ|[g
+// ÆÚ±³êéÆ«ÉAηéIuWFNgQÆðó¯æèÜ·BÚ±Éæè
+// RV
[}ͳÈIuWFNgðw·±ÆÉÈèA±¤µÄßÄIy[
+// VðÄÑo·±ÆªÅ«éÌÅ·B
+
+As shown in the following figure, a consumer receives an object
+reference when it is connected to the other port which has provider.
+After the connection established, since the consumer has a valid
+object reference, it can call operations in the remote object.
+
+#ref(serviceport_connection_and_reference_ja.png,40%,center)
+CENTER: ''Connecting service ports and object reference''
+
+// Ú±ãÍ(èÌ|[gÉKÈvoC_ª¶Ý·êÎ)RV
[}ÌIy
+// [VðÄÑo·±ÆªÅ«Ü·ªAÚ±µÄ¢È¢êAܽÍLøÈ
+// QƪZbg³êĢȢêÍARV
[}IuWFNgÍáOð°Ü
+// ·B»µÄARV
[}ðp·éêA¢ÂÚ±ªsíêé©Aܽ¢Â
+// Ú±ªØf³êé©Íª©èܹñÌÅAíɱÌáOðߨµÄKØÉ
+// ·éKvª èÜ·B
+
+After connection established, the consumer can call operations if an
+appropriate provider exists in the other port. The consumer will
+throw exceptions if the connection is not established or valid object
+reference is not set. Since you cannot know when connection is
+established or is destructed, always you have to catch exceptions from
+consumers and handle them adequately.
+
+ try
+ {
+ m_MyServiceConsumer->echo("Hello World!!");
+ }
+ catch (CORBA::SystemException &e)
+ {
+ // some logic when exception is caught
+ std::cout << "Port is not connected" << std::endl;
+ }
+ catch (...)
+ {
+ // Other exceptions
+ }
+
+// ȨAonExecute() oÖàÅáOª¶µAÖàÅߨ³êÈ©Á
+// ½êARTCÍG[óÔÖJڵܷB
+
+If an exception is thrown from the onExecute() member function, and
+the exception is not caught, RTC will go to error state.
+
+// Èãð¥Ü¦ÄAMyServiceConsumer R|[lgÀµÜ·B±ÌáÅÍA
+// onExecute() Å[U©çÌüÍÒ¿ðs¢AeIy[VÉε½R
+// }hðó¯æèAR}hɶÄ[gÌvoC_ÌIy[V
+// ðÄÑoµÊðÔ·Æ¢Á½ÈPÈàÌÅ·B
+
+Based on the above, let's implement a MyServiceConsumer component. In
+this example, the component receives commands assigned to each
+operation defined in the interface in the onExecute() function, and
+call actual operation in the remote object according to the received
+command and return results.
+
+// ÅÍAܸ[UÉpÅ«éR}hðñ¦·éª©çÝÄ¢«Ü·B
+
+So, let's see a part that shows available command to users.
+
+RTC::ReturnCode_t MyServiceConsumer::onExecute(RTC::UniqueId ec_id)
+{
+ try
+ {
+ std::cout << std::endl;
+ std::cout << "Command list: " << std::endl;
+ std::cout << " echo [msg] : echo message." << std::endl;
+ std::cout << " set_value [value]: set value." << std::endl;
+ std::cout << " get_value : get current value." << std::endl;
+ std::cout << " get_echo_history : get input messsage history." << std::endl;
+ std::cout << " get_value_history: get input value history." << std::endl;
+ std::cout << "> ";
+
+ std::string args;
+ std::string::size_type pos;
+ std::vector<std::string> argv;
+ std::getline(std::cin, args);
+
+// ܸAãÅq×½æ¤ÉRV
[}ª·éáOðߨ·é½ßÉtryßÅÍ
+// ÝÜ·BpÂ\ÈR}hXgð\¦µÄA[UÌüÍðgetline()Ö
+// Åó¯æÁĢܷB
+
+As mentioned above, in order to catch exceptions from consumer please
+put the code into a "try" block. This code is showing available
+command list and getting input from user by getline() function.
+
+
+ pos = args.find_first_of(" ");
+ if (pos != std::string::npos)
+ {
+ argv.push_back(args.substr(0, pos));
+ argv.push_back(args.substr(++pos));
+ }
+ else
+ {
+ argv.push_back(args);
+ }
+
+// ±êçÌR}h̤¿AøðæéàÌÍ echo Æ set_value ¾¯ÅA©Â
+// ±êçÌR}hÍøð꾯ÆèÜ·Bó¯æÁ½¶ñðÅÌó
+// ŪµAargv[0] = R}hAargv[1] = øÆµÄ string Ì vector É
+// i[µÜ·Becho, set_value R}hÅÍ argv[1] ðøƵÄpµA¼
+// ÌR}hÅÍPɳ·é±ÆɵܷB
+
+Only "echo" and "set_value" commands receives argument in the command
+set, and these commands have only one argument. Separating received
+character string by blank character, two strings are stored as argv[0]
+= command and argv[1] = argument. argv[1] is used as argument in the
+echo and set_value command, and for other command argv[1] is just
+ignored.
+
+
+ if (argv[0] == "echo" && argv.size() > 1)
+ {
+ CORBA::String_var retmsg;
+ retmsg = m_myservice0->echo(argv[1].c_str());
+ std::cout << "echo return: " << retmsg << std::endl;
+ return RTC::RTC_OK;
+ }
+
+// echo R}hÌÀÅ·Bargv[0] ª ''echo'' ÌêAargv[1] ðøɵ
+// Ä echo() ÖðÄÑoµÜ·Becho() ÌCORBAÌstring^Ìßèlðó¯æ
+// é½ßÌÏƵÄAretmsg ð龵ĢܷBecho() ÌßèlÌL Í
+// ±¿ç¤É éÌÅAó¯æÁ½ãÉKØÉÌæððú·éKvª éÌÅ·
+// ªAString_var ^ÌX}[g|C^ðp·éÆAsvÉÈÁ½_ÅKØ
+// ÉÌæðúðsÁÄêÜ·Bßèlð\¦µÄAreturn RTC::RTC_OK ƵÄ
+// onExecute() Öð²¯Ä¢Ü·B
+
+This is an implementation of echo command. In case that argv[0] is
+"echo", echo() function is called with argument from argv[1]. In this
+function, CORBA's string type variable "retmsg" is declared to receive
+return value from echo() function. Since the ownership of the return
+value from echo() function is here, you have to release memory
+properly after used. However, if String_var type smart pointer is
+used in this context, memory will be released automatically when it is
+not used any more. So this code just prints returned value and end
+the onExecute() function with return RTC::RTC_OK.
+
+ if (argv[0] == "set_value" && argv.size() > 1)
+ {
+ CORBA::Float val(atof(argv[1].c_str()));
+ m_myservice0->set_value(val);
+ std::cout << "Set remote value: " << val << std::endl;
+ return RTC::RTC_OK;
+ }
+
+// set_value R}hÌÀÅ·Bø argv[1] ̶ñðCORBA::Float ^É
+// Ï·µÄAset_value() Iy[VÌøÉ^¦Ä¢Ü·B
+
+This is "set_value" command implementation. After converting argument
+argv[1] to CORBA::Float, it is given to set_value() operation as an
+argument.
+
+
+ if (argv[0] == "get_value")
+ {
+ std::cout << "Current remote value: "
+ << m_myservice0->get_value() << std::endl;
+ return RTC::RTC_OK;
+ }
+
+// get_value R}hÍ set_value R}hÅÝèµ½lð澵ܷB
+// get_value() Iy[VÍAßèlª CORBA::Float ÅlnµÌ½ßIu
+// WFNgÌL ÈÇÍÁÉl¦ÈÆà\¢Ü¹ñB±±ÅÍAßèlð»
+// ÌÜÜ std::cout ÅR\[É\¦³¹Ä¢Ü·B
+
+"get_value" command gets a value that is set by "set_value" command.
+get_value() operation has a CORBA::Float return value, and because it
+is passed by value, concerning about ownership of object is not
+necessary. Here, returned value is directly printed out to the
+console by std::cout.
+
+ if (argv[0] == "get_echo_history")
+ {
+ EchoList_var elist = m_myservice0->get_echo_history();
+ for (CORBA::ULong i(0), len(elist.length(); i <len; ++i)
+ {
+ std::cout << elist[i] << std::endl;
+ }
+ return RTC::RTC_OK;
+ }
+
+// get_echo_history R}hÅÍAget_echo_history() ÌÊðó¯æèA»
+// êÜÅ echo R}hÅøÉ^¦ç꽶ñÌXgðԵĢܷB
+// get_echo_history() ÖÌßèlÍ CORBA ÌV[PX^Å é EchoList
+// Å·BV[PX^É¢ÄàX}[g|C^Å é _var ^ªè`³êÄ
+// ¢Ü·ÌÅA±êðpµÜ·BzñÌ·³ðæ¾·é½ßÌ length() Ö
+// ªpÅ«éÌÅA·³ð²×Ä for ¶Å·×ÄÌvfð\¦µÄ¢Ü·BV[
+// PX^Ì_var^ÅÍAãÌæ¤É[]Iy[^ðpµÄC¾êÌzñÌæ¤
+// ÉevfÉANZXÅ«Ü·B
+
+get_echo_history command receives a result from get_echo_history()
+operation, and print a list of strings that were given to echo-command
+before. The return value of get_echo_history() operation is EchoList
+CORBA sequence type. Since the _var smart pointer type is also
+defined for sequence type, it is used there. A "length()" function
+which returns current length of the array is available, and getting
+the length of the array by it all the values are printed out by "FOR"
+sentence. In the _var object of sequence type, "[]" operator is
+available as shown in above example, and each element can be accessed
+like in C language.
+
+ if (argv[0] == "get_value_history")
+ {
+ ValueList_var vlist = m_myservice0->get_value_history();
+ for (CORBA::ULong i(0), len(vlist.length()); i < len; ++i)
+ {
+ std::cout << vlist[i] << std::endl;
+ }
+ return RTC::RTC_OK;
+ }
+
+// ÅãÉAget_value_history R}hÅ·Bget_value_history() Iy[V
+// ðÄÑoµA±êÜÅÝè³ê½ ½èÌXgð\¦µÜ·B
+// get_value_hitory() ÖÌßèlÍ CORBA::Float ÌV[PX^Ì
+// ValueList Å·BvfÍ CORBA::Float ̽ßIuWFNgÌL Æ¢Á
+// ½±ÆÍl¦ÈÄàæ¢ÌÅ·ªAV[PX^Í»ê©gIuWFNgÅ
+// ·ÌÅAL ðl¶µÈ¯êÎÈçÈ¢Ìű±ÅÍ _var ^ÌÏÅó¯
+// æÁĢܷB
+
+Let's see get_value_history command implementation. Calling
+get_value_history() operation, it prints out a list of values which
+were set before. The return value of the get_value_history()
+operation is ValueList, which is sequence type of CORBA::Float. Since
+each element is CORBA::Float, you don't need to consider the ownership
+of objects. However, since sequence type variable is an object to be
+considered its ownership, it is assigned to _var type variable.
+
+ std::cout << "Invalid command or argument(s)." << std::endl;
+ }
+ catch (CORBA::SystemException &e)
+ {
+ std::cout << "No service connected." << std::endl;
+ }
+ return RTC::RTC_OK;
+ }
+
+// ÅãÉAãÌÇêÉàÄÍÜçÈ©Á½R}hÌêÉAbZ[Wðo
+// µÄ¢Ü·BܽARV
[}ÉQƪZbg³êĢȢêÌáOðÜ
+// ßÄߨ·é½ßÌ catch ߪ èÜ·B
+
+At the end, a message is printed out for unknown or invalid command
+case. And you can see "catch" block to catch exception from the
+consumer including reference not assigned exception.
+
+// ÈãARV
[}ÉæéIy[VÌÄÑûÉ¢ÄÈPÈáðð¦Ä
+// ྵܵ½BRV
[}ðp·éÛÉÍAK¸µàIuWFNgQƪ
+// Zbg³êÄ¢éÆÍÀçÈ¢ÌÅAK¸áOðߨµÎ·é±ÆÆAeI
+// y[VÌÄÑoµªACORBAÌ[ÉîâÄsíêé±ÆɯӵÄ
+// ¾³¢B
+
+How to call operations from consumer was explained sprinkled with some
+simple example in above. In case of using consumers, it must be noted
+that exception from consumers should always be caught and should be
+handled them since object reference is not always set to it. And note
+that every operation call would be done by CORBA's rule.
openrtm-commit メーリングリストの案内