Orocos Real-Time Toolkit
2.5.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 } 00209 00210 } 00211 00212 ActionInterface* clone() const { return new CorbaOperationCallerCall(CService::_duplicate( mfact.in() ), mop, margs, mcaller, mctt, mresult, mdocall); } 00213 00214 virtual ActionInterface* copy( std::map<const DataSourceBase*, DataSourceBase*>& alreadyCloned ) const { 00215 vector<DataSourceBase::shared_ptr> argcopy( margs.size() ); 00216 unsigned int v=0; 00217 for (vector<DataSourceBase::shared_ptr>::iterator it = argcopy.begin(); it != argcopy.end(); ++it, ++v) 00218 argcopy[v] = (*it)->copy(alreadyCloned); 00219 return new CorbaOperationCallerCall(CService::_duplicate( mfact.in() ), mop, argcopy, mcaller, mctt, mresult->copy(alreadyCloned), mdocall); 00220 } 00221 }; 00222 00223 base::DataSourceBase::shared_ptr CorbaOperationCallerFactory::produce(const std::vector<base::DataSourceBase::shared_ptr>& args, ExecutionEngine* caller) const { 00224 corba::CAnyArguments_var nargs = new corba::CAnyArguments(); 00225 nargs->length( args.size() ); 00226 00227 // this part is only done to feed to checkOperation() with some defaults. 00228 // We don't want to evaluate() the *real* data sources yet ! 00229 for (size_t i=0; i < args.size(); ++i ) { 00230 const types::TypeInfo* ti = args[i]->getTypeInfo(); 00231 CorbaTypeTransporter* ctt = dynamic_cast<CorbaTypeTransporter*>( ti->getProtocol(ORO_CORBA_PROTOCOL_ID) ); 00232 if (!ctt) 00233 throw wrong_types_of_args_exception(i+1,"type known to CORBA transport", ti->getTypeName()); 00234 DataSourceBase::shared_ptr tryout = ti->buildValue(); 00235 ctt->updateAny(tryout, nargs[i]); 00236 } 00237 // check argument types and produce: 00238 try { 00239 // will throw if wrong args. 00240 mfact->checkOperation(method.c_str(), nargs.in() ); 00241 // convert returned any to local type: 00242 const types::TypeInfo* ti = this->getArgumentType(0); 00243 if ( ti ) { 00244 if ( ti != Types()->type("void") ) { 00245 // create a method call object and a return value and let the former store results in the latter. 00246 CorbaTypeTransporter* ctt = dynamic_cast<CorbaTypeTransporter*>( ti->getProtocol(ORO_CORBA_PROTOCOL_ID) ); 00247 DataSourceBase::shared_ptr result = ti->buildValue(); 00248 // evaluate()/get() will cause the method to be called and remote return value will end up in result. 00249 return ti->buildActionAlias(new CorbaOperationCallerCall(mfact.in(),method,args,caller, ctt, result, true), result ); 00250 } else { 00251 return new DataSourceCommand( new CorbaOperationCallerCall(mfact.in(),method,args,caller, 0, DataSourceBase::shared_ptr() , true) ); 00252 } 00253 } else { 00254 // it's returning a type we don't know ! Return a DataSource<Any> 00255 DataSource<CORBA::Any_var>::shared_ptr result = new AnyDataSource( new CORBA::Any() ); 00256 // todo Provide a ctt implementation for 'CORBA::Any_var' such that the result is updated ! 00257 // The result is only for dummy reasons used now, since no ctt is set, no updating will be done. 00258 return new ActionAliasDataSource<CORBA::Any_var>(new CorbaOperationCallerCall(mfact.in(),method,args,caller, 0, result, true), result.get() ); 00259 } 00260 } catch ( corba::CNoSuchNameException& nsn ) { 00261 throw name_not_found_exception( nsn.name.in() ); 00262 } catch ( corba::CWrongNumbArgException& wa ) { 00263 throw wrong_number_of_args_exception( wa.wanted, wa.received ); 00264 } catch ( corba::CWrongTypeArgException& wta ) { 00265 throw wrong_types_of_args_exception( wta.whicharg, wta.expected.in(), wta.received.in() ); 00266 } 00267 return 0; // not reached. 00268 } 00269 00270 base::DataSourceBase::shared_ptr CorbaOperationCallerFactory::produceSend(const std::vector<base::DataSourceBase::shared_ptr>& args, ExecutionEngine* caller) const { 00271 corba::CAnyArguments_var nargs = new corba::CAnyArguments(); 00272 nargs->length( args.size() ); 00273 for (size_t i=0; i < args.size(); ++i ) { 00274 const types::TypeInfo* ti = args[i]->getTypeInfo(); 00275 CorbaTypeTransporter* ctt = dynamic_cast<CorbaTypeTransporter*>( ti->getProtocol(ORO_CORBA_PROTOCOL_ID) ); 00276 if (!ctt) 00277 throw wrong_types_of_args_exception(i+1,"type known to CORBA transport", ti->getTypeName()); 00278 DataSourceBase::shared_ptr tryout = ti->buildValue(); 00279 ctt->updateAny(tryout, nargs[i]); 00280 } 00281 try { 00282 // will throw if wrong args. 00283 mfact->checkOperation(method.c_str(), nargs.inout() ); 00284 // Will return a CSendHandle_var: 00285 DataSource<CSendHandle_var>::shared_ptr result = new ValueDataSource<CSendHandle_var>(); 00286 return new ActionAliasDataSource<CSendHandle_var>(new CorbaOperationCallerCall(mfact.in(),method,args,caller, 0, result, false), result.get() ); 00287 } catch ( corba::CNoSuchNameException& nsn ) { 00288 throw name_not_found_exception( nsn.name.in() ); 00289 } catch ( corba::CWrongNumbArgException& wa ) { 00290 throw wrong_number_of_args_exception( wa.wanted, wa.received ); 00291 } catch ( corba::CWrongTypeArgException& wta ) { 00292 throw wrong_types_of_args_exception( wta.whicharg, wta.expected.in(), wta.received.in() ); 00293 } 00294 return 0; // not reached. 00295 } 00296 00297 base::DataSourceBase::shared_ptr CorbaOperationCallerFactory::produceHandle() const { 00298 // collect expects a handle of this type. Also send returns a CSendHandle_var, which can be copied into this handle object. 00299 return new ValueDataSource<CSendHandle_var>(); 00300 } 00301 00310 class CorbaOperationCallerCollect: public DataSource<SendStatus> 00311 { 00312 CSendHandle_var msh; 00313 std::vector<base::DataSourceBase::shared_ptr> margs; 00314 DataSource<bool>::shared_ptr misblocking; 00315 mutable SendStatus mss; 00316 public: 00317 CorbaOperationCallerCollect(CSendHandle_ptr sh, 00318 std::vector<base::DataSourceBase::shared_ptr> const& args, 00319 DataSource<bool>::shared_ptr isblocking) 00320 : msh( CSendHandle::_duplicate(sh)), margs(args), misblocking(isblocking), mss(SendFailure) 00321 { 00322 } 00323 00324 ~CorbaOperationCallerCollect() { 00325 try { 00326 msh->dispose(); 00327 } catch(...) {} 00328 } 00329 00330 SendStatus value() const { return mss; } 00331 00332 SendStatus const& rvalue() const { return mss; } 00333 00334 SendStatus get() const { 00335 try { 00336 // only try to collect if we didn't do so before: 00337 if ( mss != SendSuccess ) { 00338 corba::CAnyArguments_var nargs; 00339 if ( misblocking->get() ) { 00340 mss = SendStatus( static_cast<int>(msh->collect( nargs.out() ) ) - 1 ); 00341 } else { 00342 mss = SendStatus( static_cast<int>(msh->collectIfDone( nargs.out() ) ) - 1 ); 00343 } 00344 // only convert results when we got a success: 00345 if (mss == SendSuccess) { 00346 assert( nargs->length() == margs.size() ); 00347 for (size_t i=0; i < margs.size(); ++i ) { 00348 const types::TypeInfo* ti = margs[i]->getTypeInfo(); 00349 CorbaTypeTransporter* ctt = dynamic_cast<CorbaTypeTransporter*>( ti->getProtocol(ORO_CORBA_PROTOCOL_ID) ); 00350 assert( ctt ); 00351 ctt->updateFromAny( &nargs[i], margs[i] ); 00352 } 00353 } 00354 } 00355 return mss; 00356 } catch ( corba::CWrongNumbArgException& ) { 00357 return mss; 00358 } catch ( corba::CWrongTypeArgException& ) { 00359 return mss; 00360 } 00361 } 00362 00363 DataSource<SendStatus>* clone() const { return new CorbaOperationCallerCollect(CSendHandle::_duplicate( msh.in() ), margs, misblocking); } 00364 00365 virtual DataSource<SendStatus>* copy( std::map<const DataSourceBase*, DataSourceBase*>& alreadyCloned ) const { 00366 vector<DataSourceBase::shared_ptr> argcopy( margs.size() ); 00367 unsigned int v=0; 00368 for (vector<DataSourceBase::shared_ptr>::iterator it = argcopy.begin(); it != argcopy.end(); ++it, ++v) 00369 argcopy[v] = (*it)->copy(alreadyCloned); 00370 return new CorbaOperationCallerCollect(CSendHandle::_duplicate( msh.in() ), argcopy, misblocking); 00371 } 00372 }; 00373 00374 00375 base::DataSourceBase::shared_ptr CorbaOperationCallerFactory::produceCollect(const std::vector<base::DataSourceBase::shared_ptr>& args, internal::DataSource<bool>::shared_ptr blocking) const { 00376 unsigned int expected = mfact->getCollectArity(method.c_str()); 00377 if (args.size() != expected + 1) { 00378 throw wrong_number_of_args_exception( expected + 1, args.size() ); 00379 } 00380 // isolate and check CSendHandle 00381 std::vector<base::DataSourceBase::shared_ptr> cargs( ++args.begin(), args.end() ); 00382 DataSource<CSendHandle_var>::shared_ptr ds = DataSource<CSendHandle_var>::narrow( args.begin()->get() ); 00383 if (!ds) { 00384 throw wrong_types_of_args_exception(0,"CSendHandle_var",(*args.begin())->getTypeName() ); 00385 } 00386 // check if args matches what CSendHandle expects. 00387 try { 00388 corba::CAnyArguments_var nargs = new corba::CAnyArguments(); 00389 nargs->length( cargs.size() ); 00390 for (size_t i=0; i < cargs.size(); ++i ) { 00391 const types::TypeInfo* ti = cargs[i]->getTypeInfo(); 00392 CorbaTypeTransporter* ctt = dynamic_cast<CorbaTypeTransporter*>( ti->getProtocol(ORO_CORBA_PROTOCOL_ID) ); 00393 assert( ctt ); 00394 DataSourceBase::shared_ptr tryout = ti->buildValue(); 00395 ctt->updateAny(tryout, nargs[i]); 00396 } 00397 ds->get()->checkArguments( nargs.in() ); 00398 } catch ( CWrongNumbArgException& wna) { 00399 throw wrong_number_of_args_exception(wna.wanted, wna.received); 00400 } catch ( CWrongTypeArgException& wta) { 00401 throw wrong_types_of_args_exception(wta.whicharg,wta.expected.in(), wta.received.in()); 00402 } 00403 // All went well, produce collect DataSource: 00404 return new CorbaOperationCallerCollect( ds->get().in(),cargs, blocking); 00405 } 00406 00407 #ifdef ORO_SIGNALLING_OPERATIONS 00408 Handle CorbaOperationCallerFactory::produceSignal(base::ActionInterface* func, const std::vector<base::DataSourceBase::shared_ptr>& args) const { 00409 log(Error) << "Can not attach Signal to remote Corba Operation '"<<method <<"'" <<endlog(); 00410 return Handle(); 00411 } 00412 #endif