PropertyBag.cpp

00001 /***************************************************************************
00002   tag: Peter Soetens  Mon May 10 19:10:30 CEST 2004  PropertyBag.cxx 
00003 
00004                         PropertyBag.cxx -  description
00005                            -------------------
00006     begin                : Mon May 10 2004
00007     copyright            : (C) 2004 Peter Soetens
00008     email                : peter.soetens@mech.kuleuven.ac.be
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 #ifdef ORO_PRAGMA_INTERFACE
00039 #pragma implementation
00040 #endif
00041 #include "PropertyBag.hpp"
00042 #include "Property.hpp"
00043 #include "Logger.hpp"
00044 
00045 namespace RTT
00046 {
00047 
00048     PropertyBag::PropertyBag( )
00049         : mproperties(), type("PropertyBag")
00050     {}
00051 
00052     PropertyBag::PropertyBag( const std::string& _type)
00053         : mproperties(), type(_type)
00054     {}
00055 
00056     PropertyBag::PropertyBag( const PropertyBag& orig)
00057         : mproperties( orig.getProperties() ), type( orig.getType() )
00058     {
00059     }
00060 
00061     void PropertyBag::add(PropertyBase *p)
00062     {
00063         this->addProperty(p);
00064     }
00065 
00066     void PropertyBag::remove(PropertyBase *p)
00067     {
00068         this->removeProperty(p);
00069     }
00070 
00071     bool PropertyBag::addProperty(PropertyBase *p)
00072     {
00073         if ( ! p->ready() )
00074             return false;
00075         mproperties.push_back(p);
00076         return true;
00077     }
00078 
00079     bool PropertyBag::removeProperty(PropertyBase *p)
00080     {
00081         iterator i = mproperties.begin();
00082         i = mproperties.end();
00083         i = std::find(mproperties.begin(), mproperties.end(), p);
00084         if ( i != mproperties.end() ) {
00085             mproperties.erase(i);
00086             return true;
00087         }
00088         return false;
00089     }
00090 
00091     void PropertyBag::clear()
00092     {
00093         mproperties.clear();
00094     }
00095 
00096     void PropertyBag::list(std::vector<std::string> &names) const
00097     {
00098         for (
00099              const_iterator i = mproperties.begin();
00100              i != mproperties.end();
00101              i++ )
00102             {
00103                 names.push_back( (*i)->getName() );
00104             }
00105     }
00106 
00107     std::vector<std::string> PropertyBag::list() const
00108     {
00109         std::vector<std::string> names;
00110         for (
00111              const_iterator i = mproperties.begin();
00112              i != mproperties.end();
00113              i++ )
00114             {
00115                 names.push_back( (*i)->getName() );
00116             }
00117         return names;
00118     }
00119 
00120     void PropertyBag::identify( PropertyIntrospection* pi ) const
00121     {
00122         for ( const_iterator i = mproperties.begin();
00123               i != mproperties.end();
00124               i++ )
00125             {
00126                 (*i)->identify(pi);
00127             }
00128     }
00129 
00130     void PropertyBag::identify( PropertyBagVisitor* pi ) const
00131     {
00132         for ( const_iterator i = mproperties.begin();
00133               i != mproperties.end();
00134               i++ )
00135             {
00136                 (*i)->identify(pi);
00137             }
00138     }
00139 
00140     PropertyBase* PropertyBag::find(const std::string& name) const
00141     {
00142         const_iterator i( std::find_if(mproperties.begin(), mproperties.end(), std::bind2nd(PropertyBag::FindProp(), name ) ) );
00143         if ( i != mproperties.end() )
00144             return ( *i );
00145         return 0;
00146     }
00147 
00148     PropertyBag& PropertyBag::operator=(const PropertyBag& orig)
00149     {
00150         mproperties.clear();
00151 
00152         const_iterator i = orig.getProperties().begin();
00153         while (i != orig.getProperties().end() )
00154             {
00155                 add( (*i) );
00156                 ++i;
00157             }
00158         this->setType( orig.getType() );
00159         return *this;
00160     }
00161 
00162     PropertyBag& PropertyBag::operator<<=(const PropertyBag& source)
00163     {
00164         //iterate over orig, update or clone PropertyBases
00165         const_iterator it(source.getProperties().begin());
00166         while ( it != source.getProperties().end() )
00167             {
00168                 PropertyBase* mine = find( (*it)->getName() );
00169                 if (mine != 0)
00170                     remove(mine);
00171                 add( (*it) );
00172                 ++it;
00173             }
00174         this->setType( source.getType() );
00175         return *this;
00176     }
00177 
00178     PropertyBase* findProperty(const PropertyBag& bag, const std::string& nameSequence, const std::string& separator)
00179     {
00180         PropertyBase* result;
00181         Property<PropertyBag>*  result_bag;
00182         std::string token;
00183         std::string::size_type start = 0;
00184         if ( separator.length() != 0 && nameSequence.find(separator) == 0 ) // detect 'root' attribute
00185             start = separator.length();
00186         std::string::size_type len = nameSequence.find(separator, start);
00187         if (len != std::string::npos) {
00188             token = nameSequence.substr(start,len-start);
00189             start = len + separator.length();      // reset start to next token.
00190             if ( start >= nameSequence.length() )
00191                 start = std::string::npos;
00192         }
00193         else {
00194             token = nameSequence.substr(start);
00195             start = std::string::npos; // do not look further.
00196         }
00197         result = bag.find(token);
00198         if (result != 0 ) // get the base with this name
00199         {
00200             result_bag = dynamic_cast<Property<PropertyBag>*>(result);
00201             if ( result_bag != 0 && start != std::string::npos ) {
00202                 return findProperty( result_bag->rvalue(), nameSequence.substr( start ), separator );// a bag so search recursively
00203             }
00204             else
00205                 return result; // not a bag, so it is a result.
00206         }
00207         return 0; // failure
00208     }
00209 
00210     bool refreshProperties(const PropertyBag& target, const PropertyBag& source, bool allprops)
00211     {
00212         Logger::In in("refreshProperties");
00213         //iterate over source, update PropertyBases
00214         PropertyBag::const_iterator it( target.getProperties().begin() );
00215         bool failure = false;
00216         while ( it != target.getProperties().end() )
00217         {
00218             PropertyBase* srcprop;
00219             if ( (*it)->getName() == "" ) //&& target.getType() == "Sequence" )
00220                 srcprop = source.getItem( it - target.getProperties().begin() );
00221             else
00222                 srcprop = source.find( (*it)->getName() );
00223             PropertyBase* tgtprop = *it;
00224             if (srcprop != 0)
00225             {
00226                 //std::cout <<"*******************refresh"<<std::endl;
00227                 if ( tgtprop->refresh( srcprop ) == false ) {
00228                     // try composition:
00229                     if ( tgtprop->getTypeInfo()->composeType( srcprop->getDataSource(), tgtprop->getDataSource() ) == false ) {
00230                         log(Error) << "Could not update, nor compose Property "
00231                                    << tgtprop->getType() << " "<< srcprop->getName()
00232                                    << ": type mismatch, can not refresh with type "
00233                                    << srcprop->getType() << endlog();
00234                         failure = true;
00235                     } else {
00236                         log(Debug) << "Composed Property "
00237                                       << tgtprop->getType() << " "<< srcprop->getName()
00238                                       << " from type "  << srcprop->getType() << endlog();
00239                     }
00240                 }
00241                 // ok.
00242             } else if (allprops) {
00243                 log(Error) << "Could not find Property "
00244                            << tgtprop->getType() << " "<< tgtprop->getName()
00245                            << " in source."<< endlog();
00246                 failure = true;
00247             }
00248             ++it;
00249         }
00250         return !failure;
00251     }
00252 
00253     bool refreshProperty(const PropertyBag& target, const PropertyBase& source)
00254     {
00255         PropertyBase* target_prop;
00256         // dynamic_cast ?
00257         if ( 0 != (target_prop = target.find( source.getName() ) ) )
00258             {
00259                 return target_prop->refresh( &source );
00260             }
00261         return false;
00262     }
00263 
00264     bool copyProperties(PropertyBag& target, const PropertyBag& source)
00265     {
00266         // Make a full deep copy.
00267         //iterate over source, clone all PropertyBases
00268         PropertyBag::const_iterator it( source.getProperties().begin() );
00269         while ( it != source.getProperties().end() )
00270         {
00271             // step 1 : clone a new instance (non deep copy)
00272             PropertyBase* temp = (*it)->create();
00273             // step 2 : deep copy clone with original.
00274             temp->copy( *it );
00275             // step 3 : add result to target bag.
00276             target.add( temp );
00277             ++it;
00278         }
00279         return true;
00280     }
00281 
00282     bool updateProperties(PropertyBag& target, const PropertyBag& source)
00283     {
00284         // check type consistency...
00285         if ( target.getType() == "" || target.getType() == "type_less" )
00286             target.setType("PropertyBag"); // RTT 1.2.0
00287 
00288         // if the target is of different type than source, it is replaced by source.
00289         if ( target.getType() != "PropertyBag" && target.getType() != source.getType() ) {
00290             log(Debug) << "Rebuilding typed PropertyBag."<<endlog();
00291             deletePropertyBag(target);
00292         }
00293 
00294         target.setType( source.getType() );
00295 
00296         // Make an updated if present, create if not present
00297         //iterate over source, update or clone PropertyBases
00298         PropertyBag::const_iterator it( source.getProperties().begin() );
00299         while ( it != source.getProperties().end() )
00300         {
00301             PropertyBase* mine;
00302             // if the name is not given, this bag is probably an array or sequence.
00303             if ( (*it)->getName() == "" ) // && target.getType() == "Sequence" )
00304                 mine = target.getItem( it - source.getProperties().begin() );
00305             else
00306                 mine = target.find( (*it)->getName() );
00307             if (mine != 0) {
00308 #ifndef NDEBUG
00309                 Logger::log() << Logger::Debug;
00310                 Logger::log() << "updateProperties: updating Property "
00311                               << (*it)->getType() << " "<< (*it)->getName()
00312                               << "." << Logger::endl;
00313 #endif
00314                   // no need to make new one, just update existing one
00315                 if ( mine->update( (*it) ) == false ) {
00316                     // try composition:
00317                     if ( mine->getTypeInfo()->composeType( (*it)->getDataSource(), mine->getDataSource() ) == false ) {
00318                         Logger::log() << Logger::Error;
00319                         Logger::log() << "updateProperties: Could not update, nor compose Property "
00320                                       << mine->getType() << " "<< (*it)->getName()
00321                                       << ": type mismatch, can not update with type "
00322                                       << (*it)->getType() << Logger::endl;
00323                         return false;
00324                     }
00325                 }
00326                 // ok.
00327             }
00328             else
00329             {
00330 #ifndef NDEBUG
00331                 Logger::log() << Logger::Debug;
00332                 Logger::log() << "updateProperties: created Property "
00333                               << (*it)->getType() << " "<< (*it)->getName()
00334                               << "." << Logger::endl;
00335 #endif
00336                 // step 1 : clone a new instance (non deep copy)
00337                 PropertyBase* temp = (*it)->create();
00338                 // step 2 : deep copy clone with original, will never fail.
00339                 temp->update( (*it) );
00340                 // step 3 : add result to target bag.
00341                 target.add( temp );
00342             }
00343             ++it;
00344         }
00345         return true;
00346     }
00347 
00348     bool updateProperty(PropertyBag& target, const PropertyBag& source, const std::string& name, const std::string& separator)
00349     {
00350         Logger::In in("updateProperty");
00351         // this code has been copied&modified from findProperty().
00352         PropertyBase* source_walker;
00353         PropertyBase* target_walker;
00354         std::string token;
00355         std::string::size_type start = 0;
00356         if ( separator.length() != 0 && name.find(separator) == 0 ) // detect 'root' attribute
00357             start = separator.length();
00358         std::string::size_type len = name.find(separator, start);
00359         if (len != std::string::npos) {
00360             token = name.substr(start,len-start);
00361             start = len + separator.length();      // reset start to next token.
00362             if ( start >= name.length() )
00363                 start = std::string::npos;
00364         }
00365         else {
00366             token = name.substr(start);
00367             start = std::string::npos; // do not look further.
00368         }
00369         source_walker = source.find(token);
00370         target_walker = target.find(token);
00371         if (source_walker != 0 )
00372         {
00373             if ( target_walker == 0 ) {
00374                 // if not present in target, create it !
00375                 target_walker = source_walker->create();
00376                 target.addProperty( target_walker );
00377             }
00378             Property<PropertyBag>*  source_walker_bag;
00379             Property<PropertyBag>*  target_walker_bag;
00380             source_walker_bag = dynamic_cast<Property<PropertyBag>*>(source_walker);
00381             target_walker_bag = dynamic_cast<Property<PropertyBag>*>(target_walker);
00382             if ( source_walker_bag != 0 && start != std::string::npos ) {
00383                 if ( target_walker_bag == 0 ) {
00384                     log(Error) << "Property '"<<target_walker->getName()<<"' is not a PropertyBag !"<<endlog();
00385                     return false;
00386                 }
00387                 return updateProperty( target_walker_bag->value(), source_walker_bag->rvalue(), name.substr( start ), separator );// a bag so search recursively
00388             }
00389             else {
00390                 // found it, update !
00391                 if (target_walker->update(source_walker) == false ) {
00392                     // try composition:
00393                     if ( target_walker->getTypeInfo()->composeType( source_walker->getDataSource(), target_walker->getDataSource() ) == false ) {
00394                         log(Error) << "Could not update nor compose Property "
00395                                    << target_walker->getType() << " "<< target_walker->getName()
00396                                    << ": type mismatch, can not update with type "
00397                                    << source_walker->getType() << Logger::endl;
00398                     }
00399                 }
00400                 log(Debug) << "Found Property '"<<target_walker->getName() <<"': update done." << endlog();
00401                 return true;
00402             }
00403         } else {
00404             // error wrong path, not present in source !
00405             log(Error) << "Property '"<< token <<"' is not present in the source PropertyBag !"<<endlog();
00406             return false;
00407         }
00408         // not reached.
00409         return false; // failure
00410     }
00411 
00412     bool refreshProperty(PropertyBag& target, const PropertyBag& source, const std::string& name, const std::string& separator)
00413     {
00414         Logger::In in("refreshProperty");
00415         // this code has been copied&modified from findProperty().
00416         PropertyBase* source_walker;
00417         PropertyBase* target_walker;
00418         std::string token;
00419         std::string::size_type start = 0;
00420         if ( separator.length() != 0 && name.find(separator) == 0 ) // detect 'root' attribute
00421             start = separator.length();
00422         std::string::size_type len = name.find(separator, start);
00423         if (len != std::string::npos) {
00424             token = name.substr(start,len-start);
00425             start = len + separator.length();      // reset start to next token.
00426             if ( start >= name.length() )
00427                 start = std::string::npos;
00428         }
00429         else {
00430             token = name.substr(start);
00431             start = std::string::npos; // do not look further.
00432         }
00433         source_walker = source.find(token);
00434         target_walker = target.find(token);
00435         if (source_walker != 0 )
00436         {
00437             if ( target_walker == 0 ) {
00438                 log(Error) << "Property '"<<source_walker->getName()<<"' was not found in target !"<<endlog();
00439                 return false;
00440             }
00441             Property<PropertyBag>*  source_walker_bag;
00442             Property<PropertyBag>*  target_walker_bag;
00443             source_walker_bag = dynamic_cast<Property<PropertyBag>*>(source_walker);
00444             target_walker_bag = dynamic_cast<Property<PropertyBag>*>(target_walker);
00445             if ( source_walker_bag != 0 && start != std::string::npos ) {
00446                 if ( target_walker_bag == 0 ) {
00447                     log(Error) << "Property '"<<target_walker->getName()<<"' is not a PropertyBag !"<<endlog();
00448                     return false;
00449                 }
00450                 return refreshProperty( target_walker_bag->value(), source_walker_bag->rvalue(), name.substr( start ), separator );// a bag so search recursively
00451             }
00452             else {
00453                 // found it, refresh !
00454                 if (target_walker->refresh(source_walker) == false ) {
00455                     // try composition:
00456                     if ( target_walker->getTypeInfo()->composeType( source_walker->getDataSource(), target_walker->getDataSource() ) == false ) {
00457                         log(Error) << "Could not refresh nor compose Property "
00458                                    << target_walker->getType() << " "<< target_walker->getName()
00459                                    << ": type mismatch, can not refresh with type "
00460                                    << source_walker->getType() << Logger::endl;
00461                     }
00462                 }
00463                 log(Debug) << "Found Property '"<<target_walker->getName() <<"': refresh done." << endlog();
00464                 return true;
00465             }
00466         } else {
00467             // error wrong path, not present in source !
00468             log(Error) << "Property '"<< token <<"' is not present in the source PropertyBag !"<<endlog();
00469             return false;
00470         }
00471         // not reached.
00472         return false; // failure
00473     }
00474 
00475     void deleteProperties(PropertyBag& target)
00476     {
00477         //recursive delete.
00478         PropertyBag::const_iterator it( target.getProperties().begin() );
00479         while ( it != target.getProperties().end() )
00480         {
00481             delete (*it);
00482             ++it;
00483         }
00484         target.clear();
00485     }
00486 
00487     void deletePropertyBag(PropertyBag& target)
00488     {
00489         //iterate over target, delete PropertyBases
00490         PropertyBag::const_iterator it( target.getProperties().begin() );
00491         while ( it != target.getProperties().end() )
00492         {
00493             Property<PropertyBag>* result = dynamic_cast< Property<PropertyBag>* >( *it );
00494             if ( result != 0 )
00495                 deletePropertyBag( result->value() );
00496             delete (*it);
00497             ++it;
00498         }
00499         target.clear();
00500     }
00501 
00502     void flattenPropertyBag(PropertyBag& target, const std::string& separator)
00503     {
00504         //iterate over target, recursively flatten bags.
00505         Property<PropertyBag>* result;
00506         PropertyBag::const_iterator it( target.getProperties().begin() );
00507         while ( it != target.getProperties().end() )
00508         {
00509             result = dynamic_cast< Property<PropertyBag>* >( *it );
00510             if ( result != 0 )
00511             {
00512                 flattenPropertyBag( result->value(), separator );// a bag so flatten recursively
00513                 // copy all elements from result to target.
00514                 PropertyBag::const_iterator flat_it( result->value().getProperties().begin() ) ;
00515                 if ( flat_it != result->value().getProperties().end() )
00516                 {
00517                     while (flat_it != result->value().getProperties().end() )
00518                     {
00519                         (*flat_it)->setName( result->getName() + separator + (*flat_it)->getName() );
00520                         target.add( *flat_it );
00521                         result->value().remove( *flat_it );
00522                         flat_it =  result->value().getProperties().begin();
00523                     }
00524                     it = target.getProperties().begin(); // reset iterator
00525                     continue;                            // do not increase it
00526                 } 
00527                 // the bag is empty now, but it must stay in target.
00528             }
00529             ++it;
00530         }
00531     }
00532 
00533 }

Generated on Tue Mar 25 17:41:48 2008 for OrocosReal-TimeToolkit by  doxygen 1.5.3