00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "ReportingComponent.hpp"
00029 #include <rtt/Logger.hpp>
00030 #include <rtt/Method.hpp>
00031 #include <rtt/Command.hpp>
00032
00033
00034 #include <rtt/marsh/EmptyMarshaller.hpp>
00035 #include <rtt/marsh/PropertyDemarshaller.hpp>
00036 #include <rtt/marsh/PropertyMarshaller.hpp>
00037 #include <fstream>
00038
00039 #include "ocl/ComponentLoader.hpp"
00040
00041 ORO_CREATE_COMPONENT_TYPE()
00042
00043
00044 namespace OCL
00045 {
00046 using namespace std;
00047 using namespace RTT;
00048
00049 ReportingComponent::ReportingComponent( std::string name )
00050 : TaskContext( name ),
00051 report("Report"),
00052 autotrigger("AutoTrigger","When set to 1, the data is taken upon each update(), "
00053 "otherwise, the data is only taken when the user invokes 'snapshot()'.",
00054 true),
00055 writeHeader("WriteHeader","Set to true to start each report with a header.", true),
00056 decompose("Decompose","Set to false in order to create multidimensional array in netcdf", true),
00057 synchronize_with_logging("Synchronize","Set to true if the timestamp should be synchronized with the logging",false),
00058 report_data("ReportData","A PropertyBag which defines which ports or components to report."),
00059 starttime(0),
00060 timestamp("TimeStamp","The time at which the data was read.",0.0)
00061 {
00062 this->properties()->addProperty( &autotrigger );
00063 this->properties()->addProperty( &writeHeader );
00064 this->properties()->addProperty( &decompose );
00065 this->properties()->addProperty( &synchronize_with_logging);
00066 this->properties()->addProperty( &report_data);
00067
00068
00069
00070
00071 this->methods()->addMethod( method( "snapshot", &ReportingComponent::snapshot , this),
00072 "Take a new shapshot of the data and set the timestamp." );
00073 this->methods()->addMethod( method( "screenComponent", &ReportingComponent::screenComponent , this),
00074 "Display the variables and ports of a Component.",
00075 "Component", "Name of the Component" );
00076 this->methods()->addMethod( method( "reportComponent", &ReportingComponent::reportComponent , this),
00077 "Add a Component for reporting. Only works if Component is connected.",
00078 "Component", "Name of the Component" );
00079 this->methods()->addMethod( method( "unreportComponent", &ReportingComponent::unreportComponent , this),
00080 "Remove a Component from reporting.",
00081 "Component", "Name of the Component"
00082 );
00083 this->methods()->addMethod( method( "reportData", &ReportingComponent::reportData , this),
00084 "Add a Component's DataSource for reporting. Only works if DataObject exists and Component is connected.",
00085 "Component", "Name of the Component",
00086 "DataObject", "Name of the DataObject. For example, a property or attribute." );
00087 this->methods()->addMethod( method( "unreportData", &ReportingComponent::unreportData , this),
00088 "Remove a DataObject from reporting.",
00089 "Component", "Name of the Component",
00090 "DataObject", "Name of the DataObject." );
00091 this->methods()->addMethod( method( "reportPort", &ReportingComponent::reportPort , this),
00092 "Add a Component's Connection or Port for reporting.",
00093 "Component", "Name of the Component",
00094 "Port", "Name of the Port to the connection." );
00095 this->methods()->addMethod( method( "unreportPort", &ReportingComponent::unreportPort , this),
00096 "Remove a Connection for reporting.",
00097 "Component", "Name of the Component",
00098 "Port", "Name of the Port to the connection." );
00099
00100 }
00101
00102 ReportingComponent::~ReportingComponent() {}
00103
00104
00105 bool ReportingComponent::addMarshaller( Marshaller* headerM, Marshaller* bodyM)
00106 {
00107 boost::shared_ptr<Marshaller> header(headerM);
00108 boost::shared_ptr<Marshaller> body(bodyM);
00109 if ( !header && !body)
00110 return false;
00111 if ( !header )
00112 header.reset( new EmptyMarshaller() );
00113 if ( !body)
00114 body.reset( new EmptyMarshaller());
00115
00116 marshallers.push_back( std::make_pair( header, body ) );
00117 return true;
00118 }
00119
00120 bool ReportingComponent::removeMarshallers()
00121 {
00122 marshallers.clear();
00123 return true;
00124 }
00125
00126 void ReportingComponent::cleanupHook()
00127 {
00128 root.clear();
00129 deletePropertyBag( report );
00130 }
00131
00132 bool ReportingComponent::configureHook()
00133 {
00134 Logger::In in("ReportingComponent");
00135
00136 PropertyBag bag = report_data.value();
00137
00138 if ( bag.empty() ) {
00139 log(Error) <<"No port or component configuration loaded."<<endlog();
00140 log(Error) <<"Please use marshalling.loadProperties(), reportComponent() (scripting) or LoadProperties (XML) in order to fill in ReportData." <<endlog();
00141 return false;
00142 }
00143
00144 bool ok = true;
00145 PropertyBag::const_iterator it = bag.getProperties().begin();
00146 while ( it != bag.getProperties().end() )
00147 {
00148 Property<std::string>* compName = dynamic_cast<Property<std::string>* >( *it );
00149 if ( !compName )
00150 log(Error) << "Expected Property \""
00151 << (*it)->getName() <<"\" to be of type string."<< endlog();
00152 else if ( compName->getName() == "Component" ) {
00153 ok &= this->reportComponent( compName->value() );
00154 }
00155 else if ( compName->getName() == "Port" ) {
00156 string cname = compName->value().substr(0, compName->value().find("."));
00157 string pname = compName->value().substr( compName->value().find(".")+1, string::npos);
00158 ok &= this->reportPort(cname, pname);
00159 }
00160 else if ( compName->getName() == "Data" ) {
00161 string cname = compName->value().substr(0, compName->value().find("."));
00162 string pname = compName->value().substr( compName->value().find(".")+1, string::npos);
00163 ok &= this->reportData(cname, pname);
00164 }
00165 else {
00166 log(Error) << "Expected \"Component\", \"Port\" or \"Data\", got "
00167 << compName->getName() << endlog();
00168 ok = false;
00169 }
00170 ++it;
00171 }
00172 return ok;
00173 }
00174
00175 bool ReportingComponent::screenComponent( const std::string& comp )
00176 {
00177 Logger::In in("ReportingComponent::screenComponent");
00178 log(Error) << "not implemented." <<comp<<endlog();
00179 return false;
00180 }
00181
00182 bool ReportingComponent::screenImpl( const std::string& comp, std::ostream& output)
00183 {
00184 Logger::In in("ReportingComponent");
00185 TaskContext* c = this->getPeer(comp);
00186 if ( c == 0) {
00187 log(Error) << "Unknown Component: " <<comp<<endlog();
00188 return false;
00189 }
00190 output << "Screening Component '"<< comp << "' : "<< endl << endl;
00191 PropertyBag* bag = c->properties();
00192 if (bag) {
00193 output << "Properties :" << endl;
00194 for (PropertyBag::iterator it= bag->begin(); it != bag->end(); ++it)
00195 output << " " << (*it)->getName() << " : " << (*it)->getDataSource() << endl;
00196 }
00197 AttributeRepository::AttributeNames atts = c->attributes()->names();
00198 if ( !atts.empty() ) {
00199 output << "Attributes :" << endl;
00200 for (AttributeRepository::AttributeNames::iterator it= atts.begin(); it != atts.end(); ++it)
00201 output << " " << *it << " : " << c->attributes()->getValue(*it)->getDataSource() << endl;
00202 }
00203
00204 vector<string> ports = c->ports()->getPortNames();
00205 if ( !ports.empty() ) {
00206 output << "Ports :" << endl;
00207 for (vector<string>::iterator it= ports.begin(); it != ports.end(); ++it) {
00208 output << " " << *it << " : ";
00209 if (c->ports()->getPort(*it)->connected() )
00210 output << c->ports()->getPort(*it)->connection()->getDataSource() << endl;
00211 else
00212 output << "(not connected)" << endl;
00213 }
00214 }
00215 return true;
00216 }
00217
00218 bool ReportingComponent::reportComponent( const std::string& component ) {
00219 Logger::In in("ReportingComponent");
00220
00221
00222 TaskContext* comp = this->getPeer(component);
00223 if ( !comp ) {
00224 log(Error) << "Could not report Component " << component <<" : no such peer."<<endlog();
00225 return false;
00226 }
00227 if ( !report_data.value().findValue<string>(component) )
00228 report_data.value().ownProperty( new Property<string>("Component","",component) );
00229 Ports ports = comp->ports()->getPorts();
00230 for (Ports::iterator it = ports.begin(); it != ports.end() ; ++it) {
00231 log(Debug) << "Checking port " << (*it)->getName()<<"."<<endlog();
00232 this->reportPort( component, (*it)->getName() );
00233 }
00234 return true;
00235 }
00236
00237
00238 bool ReportingComponent::unreportComponent( const std::string& component ) {
00239 TaskContext* comp = this->getPeer(component);
00240 if ( !comp ) {
00241 log(Error) << "Could not unreport Component " << component <<" : no such peer."<<endlog();
00242 return false;
00243 }
00244 Ports ports = comp->ports()->getPorts();
00245 for (Ports::iterator it = ports.begin(); it != ports.end() ; ++it) {
00246 this->unreportDataSource( component + "." + (*it)->getName() );
00247 report_data.value().removeProperty( report_data.value().findValue<string>(component));
00248 if ( this->ports()->getPort( (*it)->getName() ) ) {
00249
00250 }
00251 }
00252 return true;
00253 }
00254
00255
00256 bool ReportingComponent::reportPort(const std::string& component, const std::string& port ) {
00257 Logger::In in("ReportingComponent");
00258 TaskContext* comp = this->getPeer(component);
00259 if ( !comp ) {
00260 log(Error) << "Could not report Component " << component <<" : no such peer."<<endlog();
00261 return false;
00262 }
00263 PortInterface* porti = comp->ports()->getPort(port);
00264 if ( !porti ) {
00265 log(Error) << "Could not report Port " << port
00266 <<" : no such port on Component "<<component<<"."<<endlog();
00267 return false;
00268 }
00269 if ( porti->connected() ) {
00270 if ( this->reportDataSource( component + "." + port, "Port", porti->connection()->getDataSource() ) == false) {
00271 log(Error) << "Failed reporting port " << port <<endlog();
00272 return false;
00273 }
00274
00275 log(Info) << "Reporting port " << port <<" : ok."<<endlog();
00276 } else {
00277
00278
00279
00280 PortInterface* ourport = porti->antiClone();
00281 assert(ourport);
00282
00283 if ( porti->connectTo( ourport ) == false ) {
00284 delete ourport;
00285 return false;
00286 }
00287
00288 delete ourport;
00289 if (this->reportDataSource( component + "." + porti->getName(), "Port", porti->connection()->getDataSource() ) == false) {
00290 log(Error) << "Failed reporting port " << port <<endlog();
00291 return false;
00292 }
00293 log(Info) << "Created connection for port " << porti->getName()<<" : ok."<<endlog();
00294 }
00295
00296 if ( !report_data.value().findValue<string>(component) && !report_data.value().findValue<string>( component+"."+port) )
00297 report_data.value().ownProperty(new Property<string>("Port","",component+"."+port));
00298 return true;
00299 }
00300
00301 bool ReportingComponent::unreportPort(const std::string& component, const std::string& port ) {
00302 return this->unreportDataSource( component + "." + port ) && report_data.value().removeProperty( report_data.value().findValue<string>(component+"."+port));
00303 }
00304
00305
00306 bool ReportingComponent::reportData(const std::string& component,const std::string& dataname)
00307 {
00308 Logger::In in("ReportingComponent");
00309 TaskContext* comp = this->getPeer(component);
00310 if ( !comp ) {
00311 log(Error) << "Could not report Component " << component <<" : no such peer."<<endlog();
00312 return false;
00313 }
00314
00315 if ( comp->attributes()->getValue( dataname ) ) {
00316 if (this->reportDataSource( component + "." + dataname, "Data",
00317 comp->attributes()->getValue( dataname )->getDataSource() ) == false) {
00318 log(Error) << "Failed reporting data " << dataname <<endlog();
00319 return false;
00320 }
00321 }
00322
00323
00324 if ( comp->properties() && comp->properties()->find( dataname ) ) {
00325 if (this->reportDataSource( component + "." + dataname, "Data",
00326 comp->properties()->find( dataname )->getDataSource() ) == false) {
00327 log(Error) << "Failed reporting data " << dataname <<endlog();
00328 return false;
00329 }
00330 }
00331
00332
00333 if ( !report_data.value().findValue<string>( component+"."+dataname) )
00334 report_data.value().ownProperty(new Property<string>("Data","",component+"."+dataname));
00335 return true;
00336 }
00337
00338 bool ReportingComponent::unreportData(const std::string& component,const std::string& datasource) {
00339 return this->unreportDataSource( component +"." + datasource) && report_data.value().removeProperty( report_data.value().findValue<string>(component+"."+datasource));
00340 }
00341
00342 void ReportingComponent::snapshot() {
00343 timestamp = TimeService::Instance()->secondsSince( starttime );
00344
00345
00346 for(Reports::iterator it = root.begin(); it != root.end(); ++it )
00347 (it->get<2>())->execute();
00348 if( this->engine()->getActivity() )
00349 this->engine()->getActivity()->trigger();
00350 }
00351
00352 bool ReportingComponent::reportDataSource(std::string tag, std::string type, DataSourceBase::shared_ptr orig)
00353 {
00354
00355 for (Reports::iterator it = root.begin();
00356 it != root.end(); ++it)
00357 if ( it->get<0>() == tag ) {
00358 return true;
00359 }
00360
00361
00362
00363 DataSourceBase::shared_ptr clone = orig->getTypeInfo()->buildValue();
00364 if ( !clone ) {
00365 log(Error) << "Could not report '"<< tag <<"' : unknown type." << endlog();
00366 return false;
00367 }
00368 try {
00369 boost::shared_ptr<CommandInterface> comm( clone->updateCommand( orig.get() ) );
00370 assert( comm );
00371 root.push_back( boost::make_tuple( tag, orig, comm, clone, type ) );
00372 } catch ( bad_assignment& ba ) {
00373 log(Error) << "Could not report '"<< tag <<"' : failed to create Command." << endlog();
00374 return false;
00375 }
00376 return true;
00377 }
00378
00379 bool ReportingComponent::unreportDataSource(std::string tag)
00380 {
00381 for (Reports::iterator it = root.begin();
00382 it != root.end(); ++it)
00383 if ( it->get<0>() == tag ) {
00384 root.erase(it);
00385 return true;
00386 }
00387 return false;
00388 }
00389
00390 bool ReportingComponent::startHook() {
00391 Logger::In in("ReportingComponent");
00392 if (marshallers.begin() == marshallers.end()) {
00393 log(Error) << "Need at least one marshaller to write reports." <<endlog();
00394 return false;
00395 }
00396
00397
00398 if (writeHeader.get()) {
00399 this->snapshot();
00400 this->makeReport();
00401 for(Marshallers::iterator it=marshallers.begin(); it != marshallers.end(); ++it) {
00402 it->first->serialize( report );
00403 it->first->flush();
00404 }
00405 this->cleanReport();
00406 }
00407 if(synchronize_with_logging.get())
00408 starttime = Logger::Instance()->getReferenceTime();
00409 else
00410 starttime = TimeService::Instance()->getTicks();
00411 return true;
00412 }
00413
00414 void ReportingComponent::makeReport()
00415 {
00416 report.add( timestamp.clone() );
00417 for(Reports::iterator it = root.begin(); it != root.end(); ++it ) {
00418 DataSourceBase::shared_ptr clone = it->get<3>();
00419 Property<PropertyBag> subbag( it->get<0>(), "");
00420 if ( decompose.get() && clone->getTypeInfo()->decomposeType( clone, subbag.value() ) )
00421 report.add( subbag.clone() );
00422 else
00423 report.add( clone->getTypeInfo()->buildProperty(it->get<0>(), "", clone) );
00424 }
00425 }
00426
00427 void ReportingComponent::cleanReport()
00428 {
00429
00430 deletePropertyBag( report );
00431 }
00432
00433 void ReportingComponent::updateHook() {
00434
00435 if ( autotrigger )
00436 this->snapshot();
00437
00438
00439 this->makeReport();
00440
00441
00442
00443 for(Marshallers::iterator it=marshallers.begin(); it != marshallers.end(); ++it) {
00444 it->second->serialize( report );
00445 it->second->flush();
00446 }
00447
00448 this->cleanReport();
00449 }
00450
00451 void ReportingComponent::stopHook() {
00452
00453 for(Marshallers::iterator it=marshallers.begin(); it != marshallers.end(); ++it) {
00454 it->second->flush();
00455 }
00456 }
00457
00458 }