Orocos Real-Time Toolkit
2.6.0
|
00001 /*************************************************************************** 00002 tag: The SourceWorks Tue Sep 7 00:55:18 CEST 2010 CorbaOperationCallerFactory.cpp 00003 00004 CorbaOperationCallerFactory.cpp - description 00005 ------------------- 00006 begin : Tue September 07 2010 00007 copyright : (C) 2010 The SourceWorks 00008 email : peter@thesourceworks.com 00009 00010 *************************************************************************** 00011 * This library is free software; you can redistribute it and/or * 00012 * modify it under the terms of the GNU General Public * 00013 * License as published by the Free Software Foundation; * 00014 * version 2 of the License. * 00015 * * 00016 * As a special exception, you may use this file as part of a free * 00017 * software library without restriction. Specifically, if other files * 00018 * instantiate templates or use macros or inline functions from this * 00019 * file, or you compile this file and link it with other files to * 00020 * produce an executable, this file does not by itself cause the * 00021 * resulting executable to be covered by the GNU General Public * 00022 * License. This exception does not however invalidate any other * 00023 * reasons why the executable file might be covered by the GNU General * 00024 * Public License. * 00025 * * 00026 * This library is distributed in the hope that it will be useful, * 00027 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00028 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00029 * Lesser General Public License for more details. * 00030 * * 00031 * You should have received a copy of the GNU General Public * 00032 * License along with this library; if not, write to the Free Software * 00033 * Foundation, Inc., 59 Temple Place, * 00034 * Suite 330, Boston, MA 02111-1307 USA * 00035 * * 00036 ***************************************************************************/ 00037 00038 00039 #include "CorbaOperationCallerFactory.hpp" 00040 #include "AnyDataSource.hpp" 00041 #include "CorbaLib.hpp" 00042 00043 #include "../../types/Types.hpp" 00044 #include "../../internal/DataSources.hpp" 00045 #include "../../internal/DataSourceCommand.hpp" 00046 #include "../../SendStatus.hpp" 00047 #include "../../Handle.hpp" 00048 00049 using namespace std; 00050 using namespace RTT; 00051 using namespace RTT::detail; 00052 00053 CorbaOperationCallerFactory::CorbaOperationCallerFactory( const std::string& method_name, corba::CService_ptr fact, PortableServer::POA_ptr the_poa ) 00054 : RTT::OperationInterfacePart(), 00055 mfact(corba::CService::_duplicate(fact) ), 00056 mpoa(PortableServer::POA::_duplicate(the_poa)), 00057 method(method_name) 00058 {} 00059 00060 CorbaOperationCallerFactory::~CorbaOperationCallerFactory() {} 00061 00062 unsigned int CorbaOperationCallerFactory::arity() const { 00063 return mfact->getArity( method.c_str() ); 00064 } 00065 00066 unsigned int CorbaOperationCallerFactory::collectArity() const { 00067 return mfact->getCollectArity( method.c_str() ); 00068 } 00069 00070 const TypeInfo* CorbaOperationCallerFactory::getArgumentType(unsigned int i) const { 00071 try { 00072 CORBA::String_var tname = mfact->getArgumentType( method.c_str(), i); 00073 if ( Types()->type( tname.in() ) != 0 ) 00074 return Types()->type( tname.in() ); 00075 // locally unknown type: 00076 if (i == 0) 00077 log(Warning) << "CorbaOperationCallerFactory: remote operation's "<< method <<" return type " << tname.in() << " is unknown in this process." << endlog(); 00078 else 00079 log(Warning) << "CorbaOperationCallerFactory: remote operation's "<< method <<" argument "<< i <<" of type " << tname.in() << " is unknown in this process." << endlog(); 00080 } catch ( CNoSuchNameException& ) { 00081 assert(false); 00082 } 00083 catch ( CWrongArgumentException& wae){ 00084 log(Error) << "CorbaOperationCallerFactory::getArgumentType: Wrong arg nbr: " << wae.which_arg <<" max is " << wae.max_arg <<endlog(); 00085 } 00086 return 0; 00087 } 00088 00089 const TypeInfo* CorbaOperationCallerFactory::getCollectType(unsigned int i) const { 00090 try { 00091 CORBA::String_var tname = mfact->getCollectType( method.c_str(), i); 00092 return Types()->type( tname.in() ); 00093 } catch (...){ 00094 return 0; 00095 } 00096 } 00097 00098 00099 std::string CorbaOperationCallerFactory::resultType() const { 00100 try { 00101 CORBA::String_var result = mfact->getResultType( method.c_str() ); 00102 return std::string( result.in() ); 00103 } catch ( corba::CNoSuchNameException& nsn ) { 00104 throw name_not_found_exception( nsn.name.in() ); 00105 } 00106 return std::string(); 00107 } 00108 00109 std::string CorbaOperationCallerFactory::getName() const { 00110 return method; 00111 } 00112 00113 std::string CorbaOperationCallerFactory::description() const { 00114 try { 00115 CORBA::String_var result = mfact->getDescription( method.c_str() ); 00116 return std::string( result.in() ); 00117 } catch ( corba::CNoSuchNameException& nsn ) { 00118 throw name_not_found_exception( nsn.name.in() ); 00119 } 00120 return std::string(); 00121 } 00122 00123 std::vector< ArgumentDescription > CorbaOperationCallerFactory::getArgumentList() const { 00124 CDescriptions ret; 00125 try { 00126 corba::CDescriptions_var result = mfact->getArguments( method.c_str() ); 00127 ret.reserve( result->length() ); 00128 for (size_t i=0; i!= result->length(); ++i) 00129 ret.push_back( ArgumentDescription(std::string( result[i].name.in() ), 00130 std::string( result[i].description.in() ), 00131 std::string( result[i].type.in() ) )); 00132 } catch ( corba::CNoSuchNameException& nsn ) { 00133 throw name_not_found_exception( nsn.name.in() ); 00134 } 00135 return ret; 00136 } 00137 00146 class CorbaOperationCallerCall: public ActionInterface 00147 { 00148 CService_var mfact; 00149 std::string mop; 00150 std::vector<base::DataSourceBase::shared_ptr> margs; 00151 ExecutionEngine* mcaller; 00152 base::DataSourceBase::shared_ptr mresult; 00153 corba::CAnyArguments_var nargs; 00154 // The type transporter for the return value 00155 CorbaTypeTransporter* mctt; 00156 bool mdocall; 00157 public: 00158 CorbaOperationCallerCall(CService_ptr fact, 00159 std::string op, 00160 std::vector<base::DataSourceBase::shared_ptr> const& args, 00161 ExecutionEngine* caller, 00162 CorbaTypeTransporter* ctt, 00163 base::DataSourceBase::shared_ptr result, bool docall) 00164 : mfact(CService::_duplicate(fact)), mop(op), margs(args), mcaller(caller), mresult(result), mctt(ctt), mdocall(docall) 00165 { 00166 } 00167 00168 void readArguments() { 00169 // We need to delay reading the arguments upto this point such that the args contain 00170 // the latest values. 00171 nargs = new corba::CAnyArguments(); 00172 nargs->length( margs.size() ); 00173 for (size_t i=0; i < margs.size(); ++i ) { 00174 const types::TypeInfo* ti = margs[i]->getTypeInfo(); 00175 CorbaTypeTransporter* ctt = dynamic_cast<CorbaTypeTransporter*>( ti->getProtocol(ORO_CORBA_PROTOCOL_ID) ); 00176 assert( ctt ); 00177 ctt->updateAny(margs[i], nargs[i]); 00178 } 00179 } 00180 00181 bool execute() { 00182 try { 00183 if (mdocall) { 00184 CORBA::Any_var any = mfact->callOperation( mop.c_str(), nargs.inout() ); 00185 for (size_t i=0; i < margs.size(); ++i ) { 00186 const types::TypeInfo* ti = margs[i]->getTypeInfo(); 00187 CorbaTypeTransporter* ctt = dynamic_cast<CorbaTypeTransporter*>( ti->getProtocol(ORO_CORBA_PROTOCOL_ID) ); 00188 assert( ctt ); 00189 ctt->updateFromAny( &nargs[i], margs[i] ); 00190 } 00191 // convert returned any to local type: 00192 if (mctt) 00193 return mctt->updateFromAny(&any.in(), mresult); 00194 } else { 00195 CSendHandle_var sh = mfact->sendOperation( mop.c_str(), nargs.in() ); 00196 AssignableDataSource<CSendHandle_var>::shared_ptr ads = AssignableDataSource<CSendHandle_var>::narrow( mresult.get() ); 00197 if (ads) { 00198 ads->set( sh ); // _var creates a copy of the obj reference. 00199 } 00200 } 00201 return true; 00202 } catch ( corba::CNoSuchNameException& ) { 00203 return false; 00204 } catch ( corba::CWrongNumbArgException& ) { 00205 return false; 00206 } catch ( corba::CWrongTypeArgException& ) { 00207 return false; 00208 } catch ( corba::CCallError& e) { 00209 throw std::runtime_error(std::string(e.what.in())); 00210 } 00211 } 00212 00213 ActionInterface* clone() const { return new CorbaOperationCallerCall(CService::_duplicate( mfact.in() ), mop, margs, mcaller, mctt, mresult, mdocall); } 00214 00215 virtual ActionInterface* copy( std::map<const DataSourceBase*, DataSourceBase*>& alreadyCloned ) const { 00216 vector<DataSourceBase::shared_ptr> argcopy( margs.size() ); 00217 unsigned int v=0; 00218 for (vector<DataSourceBase::shared_ptr>::iterator it = argcopy.begin(); it != argcopy.end(); ++it, ++v) 00219 argcopy[v] = (*it)->copy(alreadyCloned); 00220 return new CorbaOperationCallerCall(CService::_duplicate( mfact.in() ), mop, argcopy, mcaller, mctt, mresult->copy(alreadyCloned), mdocall); 00221 } 00222 }; 00223 00224 base::DataSourceBase::shared_ptr CorbaOperationCallerFactory::produce(const std::vector<base::DataSourceBase::shared_ptr>& args, ExecutionEngine* caller) const { 00225 corba::CAnyArguments_var nargs = new corba::CAnyArguments(); 00226 nargs->length( args.size() ); 00227 00228 // this part is only done to feed to checkOperation() with some defaults. 00229 // We don't want to evaluate() the *real* data sources yet ! 00230 for (size_t i=0; i < args.size(); ++i ) { 00231 const types::TypeInfo* ti = args[i]->getTypeInfo(); 00232 CorbaTypeTransporter* ctt = dynamic_cast<CorbaTypeTransporter*>( ti->getProtocol(ORO_CORBA_PROTOCOL_ID) ); 00233 if (!ctt) 00234 throw wrong_types_of_args_exception(i+1,"type known to CORBA transport", ti->getTypeName()); 00235 DataSourceBase::shared_ptr tryout = ti->buildValue(); 00236 ctt->updateAny(tryout, nargs[i]); 00237 } 00238 // check argument types and produce: 00239 try { 00240 // will throw if wrong args. 00241 mfact->checkOperation(method.c_str(), nargs.in() ); 00242 // convert returned any to local type: 00243 const types::TypeInfo* ti = this->getArgumentType(0); 00244 if ( ti ) { 00245 if ( ti != Types()->type("void") ) { 00246 // create a method call object and a return value and let the former store results in the latter. 00247 CorbaTypeTransporter* ctt = dynamic_cast<CorbaTypeTransporter*>( ti->getProtocol(ORO_CORBA_PROTOCOL_ID) ); 00248 DataSourceBase::shared_ptr result = ti->buildValue(); 00249 // evaluate()/get() will cause the method to be called and remote return value will end up in result. 00250 return ti->buildActionAlias(new CorbaOperationCallerCall(mfact.in(),method,args,caller, ctt, result, true), result ); 00251 } else { 00252 return new DataSourceCommand( new CorbaOperationCallerCall(mfact.in(),method,args,caller, 0, DataSourceBase::shared_ptr() , true) ); 00253 } 00254 } else { 00255 // it's returning a type we don't know ! Return a DataSource<Any> 00256 DataSource<CORBA::Any_var>::shared_ptr result = new AnyDataSource( new CORBA::Any() ); 00257 // todo Provide a ctt implementation for 'CORBA::Any_var' such that the result is updated ! 00258 // The result is only for dummy reasons used now, since no ctt is set, no updating will be done. 00259 return new ActionAliasDataSource<CORBA::Any_var>(new CorbaOperationCallerCall(mfact.in(),method,args,caller, 0, result, true), result.get() ); 00260 } 00261 } catch ( corba::CNoSuchNameException& nsn ) { 00262 throw name_not_found_exception( nsn.name.in() ); 00263 } catch ( corba::CWrongNumbArgException& wa ) { 00264 throw wrong_number_of_args_exception( wa.wanted, wa.received ); 00265 } catch ( corba::CWrongTypeArgException& wta ) { 00266 throw wrong_types_of_args_exception( wta.whicharg, wta.expected.in(), wta.received.in() ); 00267 } 00268 return 0; // not reached. 00269 } 00270 00271 base::DataSourceBase::shared_ptr CorbaOperationCallerFactory::produceSend(const std::vector<base::DataSourceBase::shared_ptr>& args, ExecutionEngine* caller) const { 00272 corba::CAnyArguments_var nargs = new corba::CAnyArguments(); 00273 nargs->length( args.size() ); 00274 for (size_t i=0; i < args.size(); ++i ) { 00275 const types::TypeInfo* ti = args[i]->getTypeInfo(); 00276 CorbaTypeTransporter* ctt = dynamic_cast<CorbaTypeTransporter*>( ti->getProtocol(ORO_CORBA_PROTOCOL_ID) ); 00277 if (!ctt) 00278 throw wrong_types_of_args_exception(i+1,"type known to CORBA transport", ti->getTypeName()); 00279 DataSourceBase::shared_ptr tryout = ti->buildValue(); 00280 ctt->updateAny(tryout, nargs[i]); 00281 } 00282 try { 00283 // will throw if wrong args. 00284 mfact->checkOperation(method.c_str(), nargs.inout() ); 00285 // Will return a CSendHandle_var: 00286 DataSource<CSendHandle_var>::shared_ptr result = new ValueDataSource<CSendHandle_var>(); 00287 return new ActionAliasDataSource<CSendHandle_var>(new CorbaOperationCallerCall(mfact.in(),method,args,caller, 0, result, false), result.get() ); 00288 } catch ( corba::CNoSuchNameException& nsn ) { 00289 throw name_not_found_exception( nsn.name.in() ); 00290 } catch ( corba::CWrongNumbArgException& wa ) { 00291 throw wrong_number_of_args_exception( wa.wanted, wa.received ); 00292 } catch ( corba::CWrongTypeArgException& wta ) { 00293 throw wrong_types_of_args_exception( wta.whicharg, wta.expected.in(), wta.received.in() ); 00294 } 00295 return 0; // not reached. 00296 } 00297 00298 base::DataSourceBase::shared_ptr CorbaOperationCallerFactory::produceHandle() const { 00299 // collect expects a handle of this type. Also send returns a CSendHandle_var, which can be copied into this handle object. 00300 return new ValueDataSource<CSendHandle_var>(); 00301 } 00302 00311 class CorbaOperationCallerCollect: public DataSource<SendStatus> 00312 { 00313 CSendHandle_var msh; 00314 std::vector<base::DataSourceBase::shared_ptr> margs; 00315 DataSource<bool>::shared_ptr misblocking; 00316 mutable SendStatus mss; 00317 public: 00318 CorbaOperationCallerCollect(CSendHandle_ptr sh, 00319 std::vector<base::DataSourceBase::shared_ptr> const& args, 00320 DataSource<bool>::shared_ptr isblocking) 00321 : msh( CSendHandle::_duplicate(sh)), margs(args), misblocking(isblocking), mss(SendFailure) 00322 { 00323 } 00324 00325 ~CorbaOperationCallerCollect() { 00326 try { 00327 msh->dispose(); 00328 } catch(...) {} 00329 } 00330 00331 SendStatus value() const { return mss; } 00332 00333 SendStatus const& rvalue() const { return mss; } 00334 00335 SendStatus get() const { 00336 try { 00337 // only try to collect if we didn't do so before: 00338 if ( mss != SendSuccess ) { 00339 corba::CAnyArguments_var nargs; 00340 if ( misblocking->get() ) { 00341 mss = SendStatus( static_cast<int>(msh->collect( nargs.out() ) ) - 1 ); 00342 } else { 00343 mss = SendStatus( static_cast<int>(msh->collectIfDone( nargs.out() ) ) - 1 ); 00344 } 00345 // only convert results when we got a success: 00346 if (mss == SendSuccess) { 00347 assert( nargs->length() == margs.size() ); 00348 for (size_t i=0; i < margs.size(); ++i ) { 00349 const types::TypeInfo* ti = margs[i]->getTypeInfo(); 00350 CorbaTypeTransporter* ctt = dynamic_cast<CorbaTypeTransporter*>( ti->getProtocol(ORO_CORBA_PROTOCOL_ID) ); 00351 assert( ctt ); 00352 ctt->updateFromAny( &nargs[i], margs[i] ); 00353 } 00354 } 00355 } 00356 return mss; 00357 } catch ( corba::CWrongNumbArgException& ) { 00358 return mss; 00359 } catch ( corba::CWrongTypeArgException& ) { 00360 return mss; 00361 } catch ( corba::CCallError& e) { 00362 throw std::runtime_error(std::string(e.what.in())); 00363 } 00364 } 00365 00366 DataSource<SendStatus>* clone() const { return new CorbaOperationCallerCollect(CSendHandle::_duplicate( msh.in() ), margs, misblocking); } 00367 00368 virtual DataSource<SendStatus>* copy( std::map<const DataSourceBase*, DataSourceBase*>& alreadyCloned ) const { 00369 vector<DataSourceBase::shared_ptr> argcopy( margs.size() ); 00370 unsigned int v=0; 00371 for (vector<DataSourceBase::shared_ptr>::iterator it = argcopy.begin(); it != argcopy.end(); ++it, ++v) 00372 argcopy[v] = (*it)->copy(alreadyCloned); 00373 return new CorbaOperationCallerCollect(CSendHandle::_duplicate( msh.in() ), argcopy, misblocking); 00374 } 00375 }; 00376 00377 00378 base::DataSourceBase::shared_ptr CorbaOperationCallerFactory::produceCollect(const std::vector<base::DataSourceBase::shared_ptr>& args, internal::DataSource<bool>::shared_ptr blocking) const { 00379 unsigned int expected = mfact->getCollectArity(method.c_str()); 00380 if (args.size() != expected + 1) { 00381 throw wrong_number_of_args_exception( expected + 1, args.size() ); 00382 } 00383 // isolate and check CSendHandle 00384 std::vector<base::DataSourceBase::shared_ptr> cargs( ++args.begin(), args.end() ); 00385 DataSource<CSendHandle_var>::shared_ptr ds = DataSource<CSendHandle_var>::narrow( args.begin()->get() ); 00386 if (!ds) { 00387 throw wrong_types_of_args_exception(0,"CSendHandle_var",(*args.begin())->getTypeName() ); 00388 } 00389 // check if args matches what CSendHandle expects. 00390 try { 00391 corba::CAnyArguments_var nargs = new corba::CAnyArguments(); 00392 nargs->length( cargs.size() ); 00393 for (size_t i=0; i < cargs.size(); ++i ) { 00394 const types::TypeInfo* ti = cargs[i]->getTypeInfo(); 00395 CorbaTypeTransporter* ctt = dynamic_cast<CorbaTypeTransporter*>( ti->getProtocol(ORO_CORBA_PROTOCOL_ID) ); 00396 assert( ctt ); 00397 DataSourceBase::shared_ptr tryout = ti->buildValue(); 00398 ctt->updateAny(tryout, nargs[i]); 00399 } 00400 ds->get()->checkArguments( nargs.in() ); 00401 } catch ( CWrongNumbArgException& wna) { 00402 throw wrong_number_of_args_exception(wna.wanted, wna.received); 00403 } catch ( CWrongTypeArgException& wta) { 00404 throw wrong_types_of_args_exception(wta.whicharg,wta.expected.in(), wta.received.in()); 00405 } 00406 // All went well, produce collect DataSource: 00407 return new CorbaOperationCallerCollect( ds->get().in(),cargs, blocking); 00408 } 00409 00410 #ifdef ORO_SIGNALLING_OPERATIONS 00411 Handle CorbaOperationCallerFactory::produceSignal(base::ActionInterface* func, const std::vector<base::DataSourceBase::shared_ptr>& args) const { 00412 log(Error) << "Can not attach Signal to remote Corba Operation '"<<method <<"'" <<endlog(); 00413 return Handle(); 00414 } 00415 #endif