Orocos Real-Time Toolkit  2.5.0
PropertyComposition.cpp
00001 #include "PropertyComposition.hpp"
00002 #include "PropertyDecomposition.hpp"
00003 #include "../Logger.hpp"
00004 #include "../Property.hpp"
00005 #include "types/Types.hpp"
00006 
00007 using namespace RTT;
00008 using namespace RTT::detail;
00009 
00010 bool RTT::types::composePropertyBag( PropertyBag const& sourcebag, PropertyBag& target )
00011 {
00012     if ( !target.empty() ) {
00013         log(Error) <<"composePropertyBag: target bag must be empty."<< endlog();
00014         return false;
00015     }
00016     bool has_error = false;
00017     PropertyBag::const_iterator sit = sourcebag.begin();
00018     for( ; sit != sourcebag.end(); ++sit) {
00019         // test if it's a property bag, then we need to recurse:
00020         Property<PropertyBag> isbag;
00021         isbag = *sit; // separate assignment avoids error message !
00022         if ( isbag.ready() && isbag.value().getType() != "PropertyBag") {
00023             // typed property bag, need to compose it.
00024             TypeInfo* ti = Types()->type( isbag.value().getType() );
00025             if ( ti == 0) {
00026                 log(Error) <<"Could not compose unknown type '" << isbag.value().getType() <<"'." <<endlog();
00027                 has_error = true;
00028                 continue;
00029             }
00030             PropertyBase* tgtprop = ti->buildProperty(isbag.getName(), isbag.getDescription());
00031             if ( ti->composeType(isbag.getDataSource(), tgtprop->getDataSource()) ) {
00032                 log(Debug) << "Used user's composition function for " << tgtprop->getName() <<":"<<tgtprop->getType()<<endlog();
00033                 target.ownProperty(tgtprop);
00034             } else {
00035                 log(Error) <<"The type '" << isbag.value().getType() <<"' did not provide a type composition function, but I need one to compose it from a PropertyBag." <<endlog();
00036                 delete tgtprop;
00037                 has_error = true;
00038                 continue;
00039             }
00040         } else {
00041             if ( isbag.ready() ) {
00042                 // plain property bag, clone and recurse:
00043                 Property<PropertyBag>* newbag = new Property<PropertyBag>(isbag.getName(), isbag.getDescription());
00044                 if ( composePropertyBag(isbag.value(), newbag->value()) == false) {
00045                     delete newbag;
00046                     has_error = true;
00047                     continue;
00048                 }
00049                 target.ownProperty( newbag );
00050             } else {
00051                 // plain property, not a bag:
00052                 target.ownProperty( (*sit)->clone() );
00053             }
00054         }
00055     }
00056 
00057     return !has_error;
00058 }
00059 
00060 bool RTT::types::decomposePropertyBag( PropertyBag const& sourcebag, PropertyBag&  target)
00061 {
00062     if ( !target.empty() ) {
00063         log(Error) <<"decomposePropertyBag: target bag must be empty."<< endlog();
00064         return false;
00065     }
00066     PropertyBag::const_iterator sit = sourcebag.begin();
00067     while( sit != sourcebag.end()) {
00068         // test if it's a property bag, then we need to recurse:
00069         Property<PropertyBag> isbag;
00070         isbag = *sit; // avoid logging error
00071         if ( isbag.ready() ) {
00072             // create an empty instance to recurse in:
00073             Property<PropertyBag>* newtarget = new Property<PropertyBag>(isbag.getName(), isbag.getDescription() );
00074             target.ownProperty( newtarget );
00075             if ( decomposePropertyBag(isbag.value(), newtarget->value() ) == false) {
00076                 assert(false && "internal error in decomposePropertyBag."); // this is a best effort function.
00077             }
00078         } else {
00079             // decompose non-bag type:
00080             log(Debug) << "Checking for decompose "<< (*sit)->getName() <<endlog();
00081 
00082             // Try decomposeType() first because this is the user's implementation of decomposition:
00083             DataSourceBase::shared_ptr dsb = (*sit)->getTypeInfo()->decomposeType( (*sit)->getDataSource() );
00084             if ( dsb ) {
00085                 // check if type returned itself to avoid decomposition:
00086                 if ( dsb == (*sit)->getDataSource() ) {
00087                     // primitive type : clone the instance
00088                     target.ownProperty( (*sit)->clone() );
00089                 } else {
00090                     DataSource<PropertyBag>::shared_ptr bagds = DataSource<PropertyBag>::narrow(dsb.get());
00091                     if ( bagds ) {
00092                         // property bag ? -> further decompose
00093                         // create an empty instance to recurse in:
00094                         Property<PropertyBag>* newtarget = new Property<PropertyBag>((*sit)->getName(), (*sit)->getDescription() );
00095                         target.ownProperty( newtarget );
00096                         if ( decomposePropertyBag(bagds->rvalue(), newtarget->value() ) == false) {
00097                             assert(false && "internal error in decomposePropertyBag."); // this is a best effort function.
00098                         }
00099                     } else {
00100                         // other type ? -> add
00101                         base::PropertyBase* p = dsb->getTypeInfo()->buildProperty((*sit)->getName(), (*sit)->getDescription(), dsb);
00102                         if ( target.ownProperty( p ) == false)
00103                             log(Error) <<"Failed to create a property of decomposed data of type "<<(*sit)->getType() <<endlog();
00104                     }
00105                 }
00106             } else {
00107                 // if decomposeType() returned null, try generic decomposition, based on getMember():
00108                 Property<PropertyBag> res((*sit)->getName(), (*sit)->getDescription() );
00109                 // propertyDecomposition decomposes fully, so the result does not need to be recursed:
00110                 if ( types::propertyDecomposition(*sit, res.value() ) ) {
00111                     target.ownProperty( res.clone() );
00112                 }
00113             }
00114         }
00115         ++sit;
00116     }
00117     return true;
00118 }