From 24bb34dcff709dc3cadbf1ecfa6e94d618b8132d Mon Sep 17 00:00:00 2001 From: Charles Lesire-Cabaniols Date: Thu, 3 May 2012 16:35:11 +0200 Subject: [PATCH] Deployer: add a connectOperation method Allows to directly connect a requested operation to a provided operation without having to use the connectServices method. Typical invocation is: connectOperations("MyComponent.myRequestedService.myRequestedOperation", "MyOtherComponent.myProvidedService.myProvidedOperation") --- deployment/DeploymentComponent.cpp | 69 +++++++++++++++++++++++++++++++++++- deployment/DeploymentComponent.hpp | 17 +++++++++ deployment/tests/main.cpp | 40 +++++++++++++++++++++ 3 files changed, 125 insertions(+), 1 deletions(-) diff --git a/deployment/DeploymentComponent.cpp b/deployment/DeploymentComponent.cpp index 5c8aa32..6b83a61 100644 --- a/deployment/DeploymentComponent.cpp +++ b/deployment/DeploymentComponent.cpp @@ -37,8 +37,9 @@ #include #include #include -#include +#include +#include #include #include @@ -154,6 +155,7 @@ namespace OCL .arg("policy", "The connection policy which serves to describe the stream to be created. Use 'ConnPolicy()' to use the default."); this->addOperation("connectServices", (bool(DeploymentComponent::*)(const std::string&, const std::string&))&DeploymentComponent::connectServices, this, ClientThread).doc("Connect the matching provides/requires services of two Components known to this Component.").arg("One", "The first component.").arg("Two", "The second component."); + this->addOperation("connectOperations", &DeploymentComponent::connectOperations, this, ClientThread).doc("Connect the matching provides/requires operations of two Components known to this Component.").arg("Requested", "The requested operation (dot-separated path).").arg("Provided", "The provided operation (dot-separated path)."); this->addOperation("addPeer", cp, this, ClientThread).doc("Add a peer to a Component.").arg("From", "The first component.").arg("To", "The other component."); typedef void(DeploymentComponent::*RPFun)(const std::string&); @@ -304,6 +306,35 @@ namespace OCL return ret; } + ServiceRequester* DeploymentComponent::stringToServiceRequester(string const& names) { + std::vector strs; + boost::split(strs, names, boost::is_any_of(".")); + + string component = strs.front(); + if (!hasPeer(component) && component != this->getName() ) { + log(Error) << "No such component: '"<< component <<"'" <getName() ? getPeer(component)->requires() : this->requires()); + + // remove component name: + strs.erase( strs.begin() ); + + // iterate over remainders: + while ( !strs.empty() && ret) { + ret = ret->requires( strs.front() ); + if (ret) + strs.erase( strs.begin() ); + } + if (!ret) { + log(Error) <<"No such service: '"<< strs.front() <<"' while looking for service '"<< names<<"'"< strs; boost::split(strs, names, boost::is_any_of(".")); @@ -464,6 +495,42 @@ namespace OCL return a->connectServices(b); } + bool DeploymentComponent::connectOperations(const std::string& required, const std::string& provided) + { + RTT::Logger::In in("DeploymentComponent::connectOperations"); + // Required service + boost::iterator_range reqs = boost::algorithm::find_last(required, "."); + std::string reqs_name(required.begin(), reqs.begin()); + std::string rop_name(reqs.begin()+1, required.end()); + log(Debug) << "Looking for required operation " << rop_name << " in service " << reqs_name << endlog(); + ServiceRequester* r = this->stringToServiceRequester(reqs_name); + // Provided service + boost::iterator_range pros = boost::algorithm::find_last(provided, "."); + std::string pros_name(provided.begin(), pros.begin()); + std::string pop_name(pros.begin()+1, provided.end()); + log(Debug) << "Looking for provided operation " << pop_name << " in service " << pros_name << endlog(); + Service::shared_ptr p = this->stringToService(pros_name); + // Requested operation + RTT::base::OperationCallerBaseInvoker* rop = r->getOperationCaller(rop_name); + if (! rop) { + log(Error) << "No requested operation " << rop_name << " found in service " << reqs_name << endlog(); + return false; + } + if ( rop->ready() ) { + log(Error) << "Requested operation " << rop_name << " already connected to a provided operation!" << endlog(); + return false; + } + // Provided operation + if (! p->hasOperation(pop_name)) { + log(Error) << "No provided operation " << pop_name << " found in service " << pros_name << endlog(); + return false; + } + // Connection + rop->setImplementation(p->getLocalOperation( pop_name ), r->getServiceOwner()->engine()); + if ( rop->ready() ) + log(Debug) << "Successfully set up OperationCaller for operation " << rop_name << endlog(); + return rop->ready(); + } int string_to_oro_sched(const std::string& sched) { if ( sched == "ORO_SCHED_OTHER" ) diff --git a/deployment/DeploymentComponent.hpp b/deployment/DeploymentComponent.hpp index 1305e7d..3a8a1ab 100644 --- a/deployment/DeploymentComponent.hpp +++ b/deployment/DeploymentComponent.hpp @@ -210,6 +210,15 @@ namespace OCL */ Service::shared_ptr stringToService(string const& names); /** + * Converts a dot-separated path to a service to a ServiceRequester + * object. + * @param name a dot-separated path name to a service. The first + * part of the name must be the component name. For example 'Controller.arm'. + * @return null if the service could not be found, the service + * otherwise + */ + ServiceRequester* stringToServiceRequester(std::string const& names); + /** * Converts a dot-separated path to a service to a Port * object. * @param name a dot-separated path name to a port. The first @@ -338,6 +347,14 @@ namespace OCL bool connectServices(const std::string& one, const std::string& other); /** + * Connects a required operation to a provided operation. + * @param required The dot-separated name of a required operation + * @param provided The dot-separated name of a provided operation + * @return true if required is connected to provided + */ + bool connectOperations(const std::string& required, const std::string& provided); + + /** * Make one component a peer of the other, in one direction, such * that one can use the services of the other. * diff --git a/deployment/tests/main.cpp b/deployment/tests/main.cpp index 8c931c7..068a825 100644 --- a/deployment/tests/main.cpp +++ b/deployment/tests/main.cpp @@ -36,17 +36,57 @@ public: } }; +class HelloProvider + : public RTT::TaskContext +{ +public: + bool hello() { + RTT::Logger::In("connectOperations Test"); + log(Info) << "Hello World!" << endlog(); + return true; + } + + HelloProvider() + : RTT::TaskContext("HelloProvider") + { + this->provides("hello_service")->addOperation("hello", &HelloProvider::hello, this); + } +}; + +class HelloRequester + : public RTT::TaskContext +{ +public: + RTT::OperationCaller helloworld; + HelloRequester() + : RTT::TaskContext("HelloRequester"), + helloworld("helloworld") + { + this->requires()->addOperationCaller(helloworld); + } + void virtual updateHook() { + helloworld(); + } +}; + int ORO_main(int, char**) { + RTT::Logger::Instance()->setLogLevel(RTT::Logger::Info); + MyTask t1("ComponentA"); MyTask t2("ComponentB"); MyTask t3("ComponentC"); + HelloProvider p; + HelloRequester r; + { DeploymentComponent dc; dc.addPeer( &t1 ); dc.addPeer( &t2 ); dc.addPeer( &t3 ); + dc.addPeer( &p ); + dc.addPeer( &r ); dc.kickStart("deployment.cpf"); TaskBrowser tb(&dc); -- 1.7.5.4