Orocos Real-Time Toolkit  2.8.3
CorbaOperationCallerFactory.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: The SourceWorks Tue Sep 7 00:55:18 CEST 2010 CorbaOperationCallerFactory.cpp
3 
4  CorbaOperationCallerFactory.cpp - description
5  -------------------
6  begin : Tue September 07 2010
7  copyright : (C) 2010 The SourceWorks
8  email : peter@thesourceworks.com
9 
10  ***************************************************************************
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU General Public *
13  * License as published by the Free Software Foundation; *
14  * version 2 of the License. *
15  * *
16  * As a special exception, you may use this file as part of a free *
17  * software library without restriction. Specifically, if other files *
18  * instantiate templates or use macros or inline functions from this *
19  * file, or you compile this file and link it with other files to *
20  * produce an executable, this file does not by itself cause the *
21  * resulting executable to be covered by the GNU General Public *
22  * License. This exception does not however invalidate any other *
23  * reasons why the executable file might be covered by the GNU General *
24  * Public License. *
25  * *
26  * This library is distributed in the hope that it will be useful, *
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
29  * Lesser General Public License for more details. *
30  * *
31  * You should have received a copy of the GNU General Public *
32  * License along with this library; if not, write to the Free Software *
33  * Foundation, Inc., 59 Temple Place, *
34  * Suite 330, Boston, MA 02111-1307 USA *
35  * *
36  ***************************************************************************/
37 
38 
40 #include "AnyDataSource.hpp"
41 #include "CorbaLib.hpp"
42 
43 #include "../../types/Types.hpp"
44 #include "../../internal/DataSources.hpp"
45 #include "../../internal/DataSourceCommand.hpp"
46 #include "../../SendStatus.hpp"
47 #include "../../Handle.hpp"
48 
49 using namespace std;
50 using namespace RTT;
51 using namespace RTT::detail;
52 
53 CorbaOperationCallerFactory::CorbaOperationCallerFactory( const std::string& method_name, corba::CService_ptr fact, PortableServer::POA_ptr the_poa )
55  mfact(corba::CService::_duplicate(fact) ),
56  mpoa(PortableServer::POA::_duplicate(the_poa)),
57  method(method_name)
58 {}
59 
61 
62 unsigned int CorbaOperationCallerFactory::arity() const {
63  return mfact->getArity( method.c_str() );
64 }
65 
67  return mfact->getCollectArity( method.c_str() );
68 }
69 
71  try {
72  CORBA::String_var tname = mfact->getArgumentType( method.c_str(), i);
73  if ( Types()->type( tname.in() ) != 0 )
74  return Types()->type( tname.in() );
75  // locally unknown type:
76  if (i == 0)
77  log(Warning) << "CorbaOperationCallerFactory: remote operation's "<< method <<" return type " << tname.in() << " is unknown in this process." << endlog();
78  else
79  log(Warning) << "CorbaOperationCallerFactory: remote operation's "<< method <<" argument "<< i <<" of type " << tname.in() << " is unknown in this process." << endlog();
80  } catch ( CNoSuchNameException& ) {
81  assert(false);
82  }
83  catch ( CWrongArgumentException& wae){
84  log(Error) << "CorbaOperationCallerFactory::getArgumentType: Wrong arg nbr: " << wae.which_arg <<" max is " << wae.max_arg <<endlog();
85  }
86  return 0;
87 }
88 
90  try {
91  CORBA::String_var tname = mfact->getCollectType( method.c_str(), i);
92  return Types()->type( tname.in() );
93  } catch (...){
94  return 0;
95  }
96 }
97 
98 
100  try {
101  CORBA::String_var result = mfact->getResultType( method.c_str() );
102  return std::string( result.in() );
103  } catch ( corba::CNoSuchNameException& nsn ) {
104  throw name_not_found_exception( nsn.name.in() );
105  }
106  return std::string();
107 }
108 
110  return method;
111 }
112 
114  try {
115  CORBA::String_var result = mfact->getDescription( method.c_str() );
116  return std::string( result.in() );
117  } catch ( corba::CNoSuchNameException& nsn ) {
118  throw name_not_found_exception( nsn.name.in() );
119  }
120  return std::string();
121 }
122 
123 std::vector< ArgumentDescription > CorbaOperationCallerFactory::getArgumentList() const {
124  CDescriptions ret;
125  try {
126  corba::CDescriptions_var result = mfact->getArguments( method.c_str() );
127  ret.reserve( result->length() );
128  for (size_t i=0; i!= result->length(); ++i)
129  ret.push_back( ArgumentDescription(std::string( result[i].name.in() ),
130  std::string( result[i].description.in() ),
131  std::string( result[i].type.in() ) ));
132  } catch ( corba::CNoSuchNameException& nsn ) {
133  throw name_not_found_exception( nsn.name.in() );
134  }
135  return ret;
136 }
137 
146 class CorbaOperationCallerCall: public ActionInterface
147 {
148  CService_var mfact;
149  std::string mop;
150  std::vector<base::DataSourceBase::shared_ptr> margs;
151  ExecutionEngine* mcaller;
153  corba::CAnyArguments_var nargs;
154  // The type transporter for the return value
155  CorbaTypeTransporter* mctt;
156  bool mdocall;
157 public:
158  CorbaOperationCallerCall(CService_ptr fact,
159  std::string op,
160  std::vector<base::DataSourceBase::shared_ptr> const& args,
161  ExecutionEngine* caller,
162  CorbaTypeTransporter* ctt,
163  base::DataSourceBase::shared_ptr result, bool docall)
164  : mfact(CService::_duplicate(fact)), mop(op), margs(args), mcaller(caller), mresult(result), mctt(ctt), mdocall(docall)
165  {
166  }
167 
168  void readArguments() {
169  // We need to delay reading the arguments upto this point such that the args contain
170  // the latest values.
171  nargs = new corba::CAnyArguments();
172  nargs->length( margs.size() );
173  for (size_t i=0; i < margs.size(); ++i ) {
174  const types::TypeInfo* ti = margs[i]->getTypeInfo();
175  CorbaTypeTransporter* ctt = dynamic_cast<CorbaTypeTransporter*>( ti->getProtocol(ORO_CORBA_PROTOCOL_ID) );
176  assert( ctt );
177  ctt->updateAny(margs[i], nargs[i]);
178  }
179  }
180 
181  bool execute() {
182  try {
183  if (mdocall) {
184  CORBA::Any_var any = mfact->callOperation( mop.c_str(), nargs.inout() );
185  for (size_t i=0; i < margs.size(); ++i ) {
186  const types::TypeInfo* ti = margs[i]->getTypeInfo();
187  CorbaTypeTransporter* ctt = dynamic_cast<CorbaTypeTransporter*>( ti->getProtocol(ORO_CORBA_PROTOCOL_ID) );
188  assert( ctt );
189  ctt->updateFromAny( &nargs[i], margs[i] );
190  }
191  // convert returned any to local type:
192  if (mctt)
193  return mctt->updateFromAny(&any.in(), mresult);
194  } else {
195  CSendHandle_var sh = mfact->sendOperation( mop.c_str(), nargs.in() );
197  if (ads) {
198  ads->set( sh ); // _var creates a copy of the obj reference.
199  }
200  }
201  return true;
202  } catch ( corba::CNoSuchNameException& ) {
203  return false;
204  } catch ( corba::CWrongNumbArgException& ) {
205  return false;
206  } catch ( corba::CWrongTypeArgException& ) {
207  return false;
208  } catch ( corba::CCallError& e) {
209  throw std::runtime_error(std::string(e.what.in()));
210  }
211  }
212 
213  ActionInterface* clone() const { return new CorbaOperationCallerCall(CService::_duplicate( mfact.in() ), mop, margs, mcaller, mctt, mresult, mdocall); }
214 
215  virtual ActionInterface* copy( std::map<const DataSourceBase*, DataSourceBase*>& alreadyCloned ) const {
216  vector<DataSourceBase::shared_ptr> argcopy( margs.size() );
217  unsigned int v=0;
218  for (vector<DataSourceBase::shared_ptr>::iterator it = argcopy.begin(); it != argcopy.end(); ++it, ++v)
219  argcopy[v] = (*it)->copy(alreadyCloned);
220  return new CorbaOperationCallerCall(CService::_duplicate( mfact.in() ), mop, argcopy, mcaller, mctt, mresult->copy(alreadyCloned), mdocall);
221  }
222 };
223 
224 base::DataSourceBase::shared_ptr CorbaOperationCallerFactory::produce(const std::vector<base::DataSourceBase::shared_ptr>& args, ExecutionEngine* caller) const {
225  corba::CAnyArguments_var nargs = new corba::CAnyArguments();
226  nargs->length( args.size() );
227 
228  // this part is only done to feed to checkOperation() with some defaults.
229  // We don't want to evaluate() the *real* data sources yet !
230  for (size_t i=0; i < args.size(); ++i ) {
231  const types::TypeInfo* ti = args[i]->getTypeInfo();
233  if (!ctt)
234  throw wrong_types_of_args_exception(i+1,"type known to CORBA transport", ti->getTypeName());
235  DataSourceBase::shared_ptr tryout = ti->buildValue();
236  ctt->updateAny(tryout, nargs[i]);
237  }
238  // check argument types and produce:
239  try {
240  // will throw if wrong args.
241  mfact->checkOperation(method.c_str(), nargs.in() );
242  // convert returned any to local type:
243  const types::TypeInfo* ti = this->getArgumentType(0);
244  if ( ti ) {
245  if ( ti != Types()->type("void") ) {
246  // create a method call object and a return value and let the former store results in the latter.
248  DataSourceBase::shared_ptr result = ti->buildValue();
249  // evaluate()/get() will cause the method to be called and remote return value will end up in result.
250  return ti->buildActionAlias(new CorbaOperationCallerCall(mfact.in(),method,args,caller, ctt, result, true), result );
251  } else {
252  return new DataSourceCommand( new CorbaOperationCallerCall(mfact.in(),method,args,caller, 0, DataSourceBase::shared_ptr() , true) );
253  }
254  } else {
255  // it's returning a type we don't know ! Return a DataSource<Any>
256  DataSource<CORBA::Any_var>::shared_ptr result = new AnyDataSource( new CORBA::Any() );
257  // todo Provide a ctt implementation for 'CORBA::Any_var' such that the result is updated !
258  // The result is only for dummy reasons used now, since no ctt is set, no updating will be done.
259  return new ActionAliasDataSource<CORBA::Any_var>(new CorbaOperationCallerCall(mfact.in(),method,args,caller, 0, result, true), result.get() );
260  }
261  } catch ( corba::CNoSuchNameException& nsn ) {
262  throw name_not_found_exception( nsn.name.in() );
263  } catch ( corba::CWrongNumbArgException& wa ) {
265  } catch ( corba::CWrongTypeArgException& wta ) {
266  throw wrong_types_of_args_exception( wta.whicharg, wta.expected.in(), wta.received.in() );
267  }
268  return 0; // not reached.
269 }
270 
271 base::DataSourceBase::shared_ptr CorbaOperationCallerFactory::produceSend(const std::vector<base::DataSourceBase::shared_ptr>& args, ExecutionEngine* caller) const {
272  corba::CAnyArguments_var nargs = new corba::CAnyArguments();
273  nargs->length( args.size() );
274  for (size_t i=0; i < args.size(); ++i ) {
275  const types::TypeInfo* ti = args[i]->getTypeInfo();
277  if (!ctt)
278  throw wrong_types_of_args_exception(i+1,"type known to CORBA transport", ti->getTypeName());
279  DataSourceBase::shared_ptr tryout = ti->buildValue();
280  ctt->updateAny(tryout, nargs[i]);
281  }
282  try {
283  // will throw if wrong args.
284  mfact->checkOperation(method.c_str(), nargs.inout() );
285  // Will return a CSendHandle_var:
287  return new ActionAliasDataSource<CSendHandle_var>(new CorbaOperationCallerCall(mfact.in(),method,args,caller, 0, result, false), result.get() );
288  } catch ( corba::CNoSuchNameException& nsn ) {
289  throw name_not_found_exception( nsn.name.in() );
290  } catch ( corba::CWrongNumbArgException& wa ) {
292  } catch ( corba::CWrongTypeArgException& wta ) {
293  throw wrong_types_of_args_exception( wta.whicharg, wta.expected.in(), wta.received.in() );
294  }
295  return 0; // not reached.
296 }
297 
299  // collect expects a handle of this type. Also send returns a CSendHandle_var, which can be copied into this handle object.
301 }
302 
311 class CorbaOperationCallerCollect: public DataSource<SendStatus>
312 {
313  CSendHandle_var msh;
314  std::vector<base::DataSourceBase::shared_ptr> margs;
315  DataSource<bool>::shared_ptr misblocking;
316  mutable SendStatus mss;
317 public:
318  CorbaOperationCallerCollect(CSendHandle_ptr sh,
319  std::vector<base::DataSourceBase::shared_ptr> const& args,
320  DataSource<bool>::shared_ptr isblocking)
321  : msh( CSendHandle::_duplicate(sh)), margs(args), misblocking(isblocking), mss(SendFailure)
322  {
323  }
324 
326  try {
327  msh->dispose();
328  } catch(...) {}
329  }
330 
331  SendStatus value() const { return mss; }
332 
333  SendStatus const& rvalue() const { return mss; }
334 
335  SendStatus get() const {
336  try {
337  // only try to collect if we didn't do so before:
338  if ( mss != SendSuccess ) {
339  corba::CAnyArguments_var nargs;
340  if ( misblocking->get() ) {
341  mss = SendStatus( static_cast<int>(msh->collect( nargs.out() ) ) - 2 );
342  } else {
343  mss = SendStatus( static_cast<int>(msh->collectIfDone( nargs.out() ) ) - 2 );
344  }
345  // only convert results when we got a success:
346  if (mss == SendSuccess) {
347  assert( nargs->length() == margs.size() );
348  for (size_t i=0; i < margs.size(); ++i ) {
349  const types::TypeInfo* ti = margs[i]->getTypeInfo();
351  assert( ctt );
352  ctt->updateFromAny( &nargs[i], margs[i] );
353  }
354  }
355  }
356  return mss;
357  } catch ( corba::CWrongNumbArgException& ) {
358  return mss;
359  } catch ( corba::CWrongTypeArgException& ) {
360  return mss;
361  } catch ( corba::CCallError& e) {
362  throw std::runtime_error(std::string(e.what.in()));
363  }
364  }
365 
366  DataSource<SendStatus>* clone() const { return new CorbaOperationCallerCollect(CSendHandle::_duplicate( msh.in() ), margs, misblocking); }
367 
368  virtual DataSource<SendStatus>* copy( std::map<const DataSourceBase*, DataSourceBase*>& alreadyCloned ) const {
369  vector<DataSourceBase::shared_ptr> argcopy( margs.size() );
370  unsigned int v=0;
371  for (vector<DataSourceBase::shared_ptr>::iterator it = argcopy.begin(); it != argcopy.end(); ++it, ++v)
372  argcopy[v] = (*it)->copy(alreadyCloned);
373  return new CorbaOperationCallerCollect(CSendHandle::_duplicate( msh.in() ), argcopy, misblocking);
374  }
375 };
376 
377 
378 base::DataSourceBase::shared_ptr CorbaOperationCallerFactory::produceCollect(const std::vector<base::DataSourceBase::shared_ptr>& args, internal::DataSource<bool>::shared_ptr blocking) const {
379  unsigned int expected = mfact->getCollectArity(method.c_str());
380  if (args.size() != expected + 1) {
381  throw wrong_number_of_args_exception( expected + 1, args.size() );
382  }
383  // isolate and check CSendHandle
384  std::vector<base::DataSourceBase::shared_ptr> cargs( ++args.begin(), args.end() );
386  if (!ds) {
387  throw wrong_types_of_args_exception(0,"CSendHandle_var",(*args.begin())->getTypeName() );
388  }
389  // check if args matches what CSendHandle expects.
390  try {
391  corba::CAnyArguments_var nargs = new corba::CAnyArguments();
392  nargs->length( cargs.size() );
393  for (size_t i=0; i < cargs.size(); ++i ) {
394  const types::TypeInfo* ti = cargs[i]->getTypeInfo();
396  assert( ctt );
397  DataSourceBase::shared_ptr tryout = ti->buildValue();
398  ctt->updateAny(tryout, nargs[i]);
399  }
400  ds->get()->checkArguments( nargs.in() );
401  } catch ( CWrongNumbArgException& wna) {
403  } catch ( CWrongTypeArgException& wta) {
404  throw wrong_types_of_args_exception(wta.whicharg,wta.expected.in(), wta.received.in());
405  }
406  // All went well, produce collect DataSource:
407  return new CorbaOperationCallerCollect( ds->get().in(),cargs, blocking);
408 }
409 
410 #ifdef ORO_SIGNALLING_OPERATIONS
411 Handle CorbaOperationCallerFactory::produceSignal(base::ActionInterface* func, const std::vector<base::DataSourceBase::shared_ptr>& args, ExecutionEngine* subscriber) const {
412  log(Error) << "Can not attach Signal to remote Corba Operation '"<<method <<"'" <<endlog();
413  return Handle();
414 }
415 #endif
DataSource is a base class representing a generic way to read data of type T.
Definition: DataSource.hpp:94
SendStatus const & rvalue() const
Get a const reference to the value of this DataSource.
Is thrown when an operation does not exist.
Is thrown when a wrong type of arguments is provided.
virtual const types::TypeInfo * getCollectType(unsigned int i) const
Returns the type information of the n&#39;th collectable argument.
virtual base::DataSourceBase::shared_ptr produceHandle() const
Create an empty SendHandle object for this operation.
virtual unsigned int collectArity() const
Returns the number of collectable arguments of this operation&#39;s function.
Is thrown when a wrong argument number is queried.
const std::string & getTypeName() const
Return the type name which was first registered.
Definition: TypeInfo.hpp:82
sequence< any > CAnyArguments
virtual void set(param_t t)=0
Set this DataSource with a value.
Exception thrown when a factory is requested to create an object with an unknown name.
STL namespace.
virtual std::string getName() const
Returns the name of this operation.
std::vector< ArgumentDescription > CDescriptions
virtual unsigned int arity() const
Returns the arity (number of arguments) of this operation.
virtual ActionInterface * copy(std::map< const DataSourceBase *, DataSourceBase * > &alreadyCloned) const
virtual base::DataSourceBase::shared_ptr produceCollect(const std::vector< base::DataSourceBase::shared_ptr > &args, internal::DataSource< bool >::shared_ptr blocking) const
Create a DataSource for collecting the results of a Send.
base::DataSourceBase::shared_ptr buildActionAlias(base::ActionInterface *action, base::DataSourceBase::shared_ptr source) const
Returns a DataSource that first executes an action and returns the result of another data source...
Definition: TypeInfo.hpp:247
An Orocos Service which hosts operations, attributes and properties.
Definition: Service.idl:22
An execution engine serialises (executes one after the other) the execution of all commands...
SendStatus
Returns the status of a send() or collect() invocation.
Definition: SendStatus.hpp:53
virtual DataSource< T > * copy(std::map< const base::DataSourceBase *, base::DataSourceBase * > &alreadyCloned) const =0
Create a deep copy of this internal::DataSource, unless it is already cloned.
virtual std::string description() const
Returns the description of this operation.
virtual std::vector< ArgumentDescription > getArgumentList() const
Get a description of the desired arguments in the ArgumentDescription format.
DataSource< SendStatus > * clone() const
Return a shallow clone of this DataSource.
Convenient short notation for every sub-namespace of RTT.
SendStatus value() const
Return the result of the last evaluate() function.
CorbaOperationCallerCollect(CSendHandle_ptr sh, std::vector< base::DataSourceBase::shared_ptr > const &args, DataSource< bool >::shared_ptr isblocking)
A DataSource which is used to execute an action and then return the value of another DataSource...
Description of one Argument of a Command.
Returned when the result of the send() could not be collected.
Definition: SendStatus.hpp:55
A handler object that allows us to collect the results of a send.
Based on the software pattern &#39;command&#39;, this interface allows execution of action objects...
A class for representing a user type, and which can build instances of that type. ...
Definition: TypeInfo.hpp:66
This class defines the interface for creating operation objects without using C++ templates...
TypeInfoRepository::shared_ptr Types()
Obtain a pointer to the global type system.
Definition: Types.cpp:48
ActionInterface * clone() const
virtual std::string resultType() const
Return the result (return) type of this operation.
virtual base::DataSourceBase::shared_ptr produceSend(const std::vector< base::DataSourceBase::shared_ptr > &args, ExecutionEngine *caller) const
Create a DataSource for a given send operation.
boost::intrusive_ptr< DataSource< T > > shared_ptr
Definition: DataSource.hpp:115
boost::intrusive_ptr< AssignableDataSource< T > > shared_ptr
Use this type to store a pointer to an AssignableDataSource.
Definition: DataSource.hpp:198
Returned when the send() succeeded, but the operation has not yet been executed by the receiving comp...
Definition: SendStatus.hpp:57
A internal::DataSource which holds an any value and returns it in its get() method.
Is thrown when a wrong number of arguments is provided.
static AssignableDataSource< T > * narrow(base::DataSourceBase *db)
This method narrows a base::DataSourceBase to a typeded AssignableDataSource, possibly returning a ne...
Definition: DataSource.inl:72
TypeTransporter * getProtocol(int protocol_id) const
Returns this type&#39;s transport for a given protocol.
Definition: TypeInfo.cpp:150
A class that wraps a Command in a internal::DataSource<bool> interface.
#define ORO_CORBA_PROTOCOL_ID
Definition: CorbaLib.hpp:45
base::DataSourceBase::shared_ptr buildValue() const
Build a internal::ValueDataSource of this type.
Definition: TypeInfo.hpp:229
static DataSource< T > * narrow(base::DataSourceBase *db)
This method narrows a base::DataSourceBase to a typeded DataSource, possibly returning a new object...
Definition: DataSource.inl:66
Exception thrown when a factory is requested to create an object, but a wrong argument type was given...
virtual bool updateFromAny(const CORBA::Any *blob, base::DataSourceBase::shared_ptr target) const =0
Update an assignable datasource target with the contents of blob.
Exception thrown when a factory is requested to create an object but the wrong number of arguments wa...
boost::intrusive_ptr< DataSourceBase > shared_ptr
Use this type to store a pointer to a DataSourceBase.
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:51
CorbaOperationCallerCall(CService_ptr fact, std::string op, std::vector< base::DataSourceBase::shared_ptr > const &args, ExecutionEngine *caller, CorbaTypeTransporter *ctt, base::DataSourceBase::shared_ptr result, bool docall)
A simple, yet very useful DataSource, which keeps a value, and returns it in its get() method...
Definition: DataSources.hpp:60
The Handle holds the information, and allows manipulation, of a connection between a internal::Signal...
Definition: Handle.hpp:66
virtual DataSource< SendStatus > * copy(std::map< const DataSourceBase *, DataSourceBase * > &alreadyCloned) const
virtual bool updateAny(base::DataSourceBase::shared_ptr source, CORBA::Any &any) const =0
Evaluate source and update an any which contains the value of source.
virtual const types::TypeInfo * getArgumentType(unsigned int i) const
Returns the type information of the n&#39;th argument, with argument zero being the return value...
Extends the TypeTransporter in order to allow the creation of channel elements or output halves for a...
virtual base::DataSourceBase::shared_ptr produce(const std::vector< base::DataSourceBase::shared_ptr > &args, ExecutionEngine *caller) const
Create a DataSource for a given callable operation.