Orocos Real-Time Toolkit  2.5.0
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 "types/PropertyDecomposition.hpp"
00044 #include "types/Types.hpp"
00045 #include "Logger.hpp"
00046 #include <algorithm>
00047 #include "rtt-fwd.hpp"
00048 
00049 namespace RTT
00050 {
00051     using namespace detail;
00052     using namespace std;
00053 
00054     PropertyBag::PropertyBag( )
00055         : mproperties(), type("PropertyBag")
00056     {}
00057 
00058     PropertyBag::PropertyBag( const std::string& _type)
00059         : mproperties(), type(_type)
00060     {}
00061 
00062     PropertyBag::PropertyBag( const PropertyBag& orig)
00063         : mproperties(), type( orig.getType() )
00064     {
00065         for( const_iterator i = orig.mproperties.begin(); i != orig.mproperties.end(); ++i) {
00066             if ( orig.ownsProperty( *i ) ) {
00067                 PropertyBase* copy = (*i)->clone();
00068                 this->ownProperty( copy );
00069             } else {
00070                 this->add( *i );
00071             }
00072         }
00073     }
00074 
00075     PropertyBag::~PropertyBag()
00076     {
00077         this->clear();
00078     }
00079 
00080     void PropertyBag::add(PropertyBase *p)
00081     {
00082         this->addProperty(*p);
00083     }
00084 
00085     void PropertyBag::remove(PropertyBase *p)
00086     {
00087         this->removeProperty(p);
00088     }
00089 
00090     bool PropertyBag::ownProperty(PropertyBase* p)
00091     {
00092         if (p == 0)
00093             return false;
00094         if ( ! p->ready() )
00095             return false;
00096         removeProperty(p);
00097         mproperties.push_back(p);
00098         mowned_props.push_back(p);
00099         return true;
00100     }
00101 
00102     bool PropertyBag::ownsProperty(PropertyBase* p) const
00103     {
00104         if (p == 0)
00105             return false;
00106         const_iterator i = std::find(mowned_props.begin(), mowned_props.end(), p);
00107         if ( i != mowned_props.end() )
00108             return true;
00109         return false;
00110     }
00111 
00112     bool PropertyBag::addProperty(PropertyBase& p)
00113     {
00114         if (&p == 0)
00115             return false;
00116         if ( ! p.ready() )
00117             return false;
00118         mproperties.push_back(&p);
00119         return true;
00120     }
00121 
00122     bool PropertyBag::removeProperty(PropertyBase *p)
00123     {
00124         if (p == 0)
00125             return false;
00126         iterator i = std::find(mproperties.begin(), mproperties.end(), p);
00127         if ( i != mproperties.end() ) {
00128             mproperties.erase(i);
00129             i = std::find(mowned_props.begin(), mowned_props.end(), p);
00130             if ( i != mowned_props.end() ) {
00131                 delete *i;
00132                 mowned_props.erase(i); // invalidates i
00133             }
00134             return true;
00135         }
00136         return false;
00137     }
00138 
00139     void PropertyBag::clear()
00140     {
00141         mproperties.clear();
00142         for ( iterator i = mowned_props.begin();
00143               i != mowned_props.end();
00144               i++ )
00145             {
00146                 delete *i;
00147             }
00148         mowned_props.clear();
00149     }
00150 
00151     void PropertyBag::list(std::vector<std::string> &names) const
00152     {
00153         for ( const_iterator i = mproperties.begin();
00154               i != mproperties.end();
00155               i++ )
00156             {
00157                 names.push_back( (*i)->getName() );
00158             }
00159     }
00160 
00161     std::vector<std::string> PropertyBag::list() const
00162     {
00163         std::vector<std::string> names;
00164         for ( const_iterator i = mproperties.begin();
00165               i != mproperties.end();
00166               i++ )
00167             {
00168                 names.push_back( (*i)->getName() );
00169             }
00170         return names;
00171     }
00172 
00173     PropertyBag::Properties PropertyBag::getProperties(const std::string& name) const
00174     {
00175         Properties names;
00176         for ( const_iterator i = mproperties.begin();
00177               i != mproperties.end();
00178               i++ )
00179             {
00180                 if ( (*i)->getName() ==  name )
00181                     names.push_back( (*i) );
00182             }
00183         return names;
00184     }
00185 
00186 
00187     void PropertyBag::identify( PropertyIntrospection* pi ) const
00188     {
00189         for ( const_iterator i = mproperties.begin();
00190               i != mproperties.end();
00191               i++ )
00192             {
00193                 (*i)->identify(pi);
00194             }
00195     }
00196 
00197     void PropertyBag::identify( PropertyBagVisitor* pi ) const
00198     {
00199         for ( const_iterator i = mproperties.begin();
00200               i != mproperties.end();
00201               i++ )
00202             {
00203                 (*i)->identify(pi);
00204             }
00205     }
00206 
00211     struct FindProp : public std::binary_function<const base::PropertyBase*,const std::string, bool>
00212     {
00213         bool operator()(const base::PropertyBase* b1, const std::string& b2) const { return b1->getName() == b2; }
00214     };
00217     PropertyBase* PropertyBag::find(const std::string& name) const
00218     {
00219         const_iterator i( std::find_if(mproperties.begin(), mproperties.end(), std::bind2nd(FindProp(), name ) ) );
00220         if ( i != mproperties.end() )
00221             return ( *i );
00222         return 0;
00223     }
00224 
00225     base::PropertyBase* PropertyBag::getProperty(const std::string& name) const
00226     {
00227         const_iterator i( std::find_if(mproperties.begin(), mproperties.end(), std::bind2nd(FindProp(), name ) ) );
00228         if ( i != mproperties.end() )
00229             return *i;
00230         return 0;
00231     }
00232 
00233 
00234     PropertyBag& PropertyBag::operator=(const PropertyBag& orig)
00235     {
00236         if(this == &orig)
00237             return *this;
00238 
00239         this->clear();
00240 
00241         const_iterator i = orig.getProperties().begin();
00242         while (i != orig.getProperties().end() )
00243             {
00244                 add( (*i) );
00245                 ++i;
00246             }
00247         this->setType( orig.getType() );
00248         return *this;
00249     }
00250 
00251     PropertyBag& PropertyBag::operator<<=(const PropertyBag& source)
00252     {
00253         //iterate over orig, update or clone PropertyBases
00254         const_iterator it(source.getProperties().begin());
00255         while ( it != source.getProperties().end() )
00256             {
00257                 PropertyBase* mine = find( (*it)->getName() );
00258                 if (mine != 0)
00259                     remove(mine);
00260                 add( (*it) );
00261                 ++it;
00262             }
00263         this->setType( source.getType() );
00264         return *this;
00265     }
00266 
00267     template<>
00268     bool Property<PropertyBag>::update( const Property<PropertyBag>& orig)
00269     {
00270         if ( !ready() )
00271             return false;
00272         if ( _description.empty() )
00273             _description = orig.getDescription();
00274         return updateProperties( this->_value->set(), orig.rvalue() );
00275     }
00276 
00277     template<>
00278     bool Property<PropertyBag>::refresh( const Property<PropertyBag>& orig)
00279     {
00280         if ( !ready() )
00281             return false;
00282         return refreshProperties( this->_value->set(), orig.rvalue() );
00283     }
00284 
00285     template<>
00286     bool Property<PropertyBag>::copy( const Property<PropertyBag>& orig)
00287     {
00288         if ( !ready() )
00289             return false;
00290         _name = orig.getName();
00291         _description = orig.getDescription();
00292         return copyProperties( this->_value->set(), orig.rvalue() );
00293     }
00294 
00295     std::ostream& operator<<(std::ostream& os, const PropertyBag& bag) {
00296         int size = bag.size();
00297         os << "[[";
00298         for(int i=0; i != size; ++i) {
00299             os << bag.getItem(i)->getName() << "='"<< bag.getItem(i) <<"'"<<endl;
00300         }
00301         os << "]]";
00302 
00303         return os;
00304     }
00305 
00306     std::istream& operator>>(std::istream& is, PropertyBag& bag) { return is; }
00307 
00308 
00309     PropertyBase* findProperty(const PropertyBag& bag, const std::string& nameSequence, const std::string& separator)
00310     {
00311         PropertyBase* result;
00312         Property<PropertyBag>*  result_bag;
00313         std::string token;
00314         std::string::size_type start = 0;
00315         if ( separator.length() != 0 && nameSequence.find(separator) == 0 ) // detect 'root' attribute
00316             start = separator.length();
00317         std::string::size_type len = nameSequence.find(separator, start);
00318         if (len != std::string::npos) {
00319             token = nameSequence.substr(start,len-start);
00320             start = len + separator.length();      // reset start to next token.
00321             if ( start >= nameSequence.length() )
00322                 start = std::string::npos;
00323         }
00324         else {
00325             token = nameSequence.substr(start);
00326             start = std::string::npos; // do not look further.
00327         }
00328         result = bag.find(token);
00329         if (result != 0 ) // get the base with this name
00330         {
00331             result_bag = dynamic_cast<Property<PropertyBag>*>(result);
00332             if ( result_bag != 0 && start != std::string::npos ) {
00333                 return findProperty( result_bag->rvalue(), nameSequence.substr( start ), separator );// a bag so search recursively
00334             }
00335             else
00336                 return result; // not a bag, so it is a result.
00337         }
00338         return 0; // failure
00339     }
00340 
00344     void listPropertiesHelper(const PropertyBag& source, const std::string& separator, const string& prefix, vector<string>& result)
00345     {
00346         PropertyBag::const_iterator it( source.getProperties().begin() );
00347         while ( it != source.getProperties().end() ) {
00348             Property<PropertyBag>* sub = dynamic_cast<Property<PropertyBag>*>(*it);
00349             string itemname = prefix.empty() ? (*it)->getName() : prefix + separator + (*it)->getName();
00350             result.push_back( itemname );
00351             if ( sub && sub->ready() ) {
00352                 listPropertiesHelper( sub->value(), separator, itemname, result );
00353             }
00354             ++it;
00355         }
00356     }
00357 
00360     void listDescriptionsHelper(const PropertyBag& source, const std::string& separator, vector<string>& result)
00361     {
00362         PropertyBag::const_iterator it( source.getProperties().begin() );
00363         while ( it != source.getProperties().end() ) {
00364             Property<PropertyBag>* sub = dynamic_cast<Property<PropertyBag>*>(*it);
00365             result.push_back( (*it)->getDescription() );
00366             if ( sub && sub->ready() ) {
00367                 listDescriptionsHelper( sub->value(), separator, result );
00368             }
00369             ++it;
00370         }
00371     }
00374     vector<string> listProperties(const PropertyBag& source, const std::string& separator)
00375     {
00376         vector<string> result;
00377         listPropertiesHelper( source, separator, "", result);
00378         return result;
00379     }
00380 
00381     vector<string> listPropertyDescriptions(const PropertyBag& source, const std::string& separator)
00382     {
00383         vector<string> result;
00384         listDescriptionsHelper( source, separator, result);
00385         return result;
00386     }
00387 
00388     bool storeProperty(PropertyBag& bag, const std::string& path, base::PropertyBase* item, const std::string& separator )
00389     {
00390         Logger::In in("storeProperty");
00391         if ( path.empty() || path == separator )
00392             return bag.ownProperty( item );
00393         // find top-level parent
00394         string pname, rest;
00395         if ( path.find(separator) != string::npos ) {
00396             pname = path.substr( 0, path.find(separator));
00397             rest  = path.substr( path.find(separator) + separator.length() );
00398         } else {
00399             pname = path;
00400         }
00401 
00402         if ( pname.empty() && !rest.empty() )
00403             return storeProperty( bag, rest, item, separator); // recurse
00404 
00405         // pname is parent
00406         PropertyBase* parent = bag.find(pname);
00407         if (!parent) {
00408             bag.ownProperty( new Property<PropertyBag>(pname,"") );
00409             parent = bag.find(pname);
00410         }
00411         Property<PropertyBag>* parentbag = dynamic_cast<Property<PropertyBag>* >(parent);
00412         if ( !parentbag ) {
00413             log(Error) << "Path component '" << pname << "' in path '"<<path<<"' does not point to a PropertyBag."<<endlog();
00414             return false;
00415         }
00416         // recurse using new parentbag and rest.
00417         return storeProperty( parentbag->value(), rest, item, separator);
00418     }
00419 
00420     bool removeProperty(PropertyBag& bag, const std::string& path, const std::string& separator )
00421     {
00422         // empty path
00423         if ( path.empty() || path == separator )
00424             return false;
00425         // single item path
00426         if ( path.find( separator ) == string::npos)
00427             return bag.removeProperty( bag.find(path) );
00428         // multi item path
00429         string prefix = path.substr( 0, path.rfind(separator));
00430         string pname  = path.substr( path.rfind(separator) + separator.length() );
00431         // '.item' form:
00432         if ( prefix.empty() )
00433             return bag.removeProperty( bag.find(pname) );
00434         // 'bag.item' form:
00435         Property<PropertyBag> parent = findProperty( bag, prefix);
00436         if ( !parent.ready() )
00437             return false;
00438         return parent.value().removeProperty( parent.value().find( pname ) );
00439     }
00440 
00441     bool updateOrRefreshProperty( PropertyBase* source, PropertyBase* target, bool update)
00442     {
00443 #ifndef NDEBUG
00444         if (update)
00445             log(Debug) << "updateProperties: updating Property "
00446             << source->getType() << " "<< source->getName()
00447             << "." << endlog();
00448         else
00449             log(Debug) << "refreshProperties: refreshing Property "
00450             << source->getType() << " "<< source->getName()
00451             << "." << endlog();
00452 #endif
00453         // no need to make new one, just update existing one
00454         if ( (update && target->update( source ) == false ) || (!update && target->refresh( source ) == false ) ) {
00455             // try conversion
00456             DataSourceBase::shared_ptr converted = target->getTypeInfo()->convert( source->getDataSource() );
00457             if ( !converted || converted == source->getDataSource() ) {
00458                 // no conversion, try composition:
00459                 converted = target->getDataSource();
00460                 if (target->getTypeInfo()->composeType( source->getDataSource(), converted ) ) {
00461                     // case where there is a type composition -> target was updated by composeType
00462                     log(Debug) << "Composed Property "
00463                             << target->getType() << " "<< source->getName() << " to type " <<target->getType()
00464                             << " from type "  << source->getType() << endlog();
00465                     return true;
00466                 } else {
00467                     //if ( !target->getTypeInfo()->composeType( source->getDataSource(), target->getDataSource() ) )
00468                     log(Error) << (update ? "updateProperties: " : "refreshProperties: ") << " Could not update, nor convert Property "
00469                             << target->getType() << " "<< target->getName()
00470                             << ": type mismatch, can not update with "
00471                             << source->getType() << " "<< source->getName() << endlog();
00472                     return false;
00473                 }
00474             } else {
00475                 // conversion: update with converted value:
00476                 // case where there is a type conversion -> do the update of the target
00477                 // since 'converted' might be a non-Assignable DataSource, we need a work-around:
00478                 PropertyBase* dummy = target->getTypeInfo()->buildProperty("","");
00479                 dummy->getDataSource()->update( converted.get() );
00480                 assert(dummy->getTypeInfo() == converted->getTypeInfo() );
00481                 // we need to use the PropertyBase API and not the DataSource API !
00482                 if (update)
00483                     target->update(dummy);
00484                 else
00485                     target->refresh(dummy);
00486                 log(Debug) << "Converted Property "
00487                         << target->getType() << " "<< source->getName() << " to type " <<dummy->getType()
00488                         << " from type "  << source->getType() << endlog();
00489             }
00490         }
00491         return true;
00492     }
00493 
00494     bool refreshProperties(const PropertyBag& target, const PropertyBag& source, bool allprops)
00495     {
00496         Logger::In in("refreshProperties");
00497 
00498         // if the target is of different type than source, it is replaced by source.
00499         if ( target.getType() != "PropertyBag" && target.getType() != source.getType() ) {
00500             log(Error) << "Can not populate typed PropertyBag '"<< target.getType() <<"' from '"<<source.getType()<<"' (source and target type differed)."<<endlog();
00501             return false;
00502         }
00503 
00504         //iterate over source, update PropertyBases
00505         PropertyBag::const_iterator it( target.getProperties().begin() );
00506         bool failure = false;
00507         while ( it != target.getProperties().end() )
00508         {
00509             PropertyBase* srcprop;
00510             if ( (*it)->getName() == "" ) //&& target.getType() == "Sequence" )
00511                 srcprop = source.getItem( it - target.getProperties().begin() );
00512             else
00513                 srcprop = source.find( (*it)->getName() );
00514             PropertyBase* tgtprop = *it;
00515             if (srcprop != 0)
00516             {
00517                 if (updateOrRefreshProperty( srcprop, tgtprop, false) == false)
00518                     return false;
00519                 // ok.
00520             } else if (allprops) {
00521                 log(Error) << "Could not find Property "
00522                            << tgtprop->getType() << " "<< tgtprop->getName()
00523                            << " in source."<< endlog();
00524                 failure = true;
00525             }
00526             ++it;
00527         }
00528         return !failure;
00529     }
00530 
00531     bool refreshProperty(const PropertyBag& target, const PropertyBase& source)
00532     {
00533         PropertyBase* target_prop;
00534         // dynamic_cast ?
00535         if ( 0 != (target_prop = target.find( source.getName() ) ) )
00536             {
00537                 return target_prop->refresh( &source );
00538             }
00539         return false;
00540     }
00541 
00542     bool copyProperties(PropertyBag& target, const PropertyBag& source)
00543     {
00544         // Make a full deep copy.
00545         //iterate over source, clone all PropertyBases
00546         PropertyBag::const_iterator it( source.getProperties().begin() );
00547         while ( it != source.getProperties().end() )
00548         {
00549             // step 1 : clone a new instance (non deep copy)
00550             PropertyBase* temp = (*it)->create();
00551             // step 2 : deep copy clone with original.
00552             temp->copy( *it );
00553             // step 3 : add result to target bag.
00554             target.add( temp );
00555             ++it;
00556         }
00557         return true;
00558     }
00559 
00560 
00561     bool updateProperties(PropertyBag& target, const PropertyBag& source)
00562     {
00563         // check type consistency...
00564         if ( target.getType() == "" || target.getType() == "type_less" )
00565             target.setType("PropertyBag"); // RTT 1.2.0
00566 
00567         // if the target is of different type than source, it is replaced by source.
00568         if ( target.getType() != "PropertyBag" && target.getType() != source.getType() ) {
00569             log(Error) << "Can not populate typed PropertyBag '"<< target.getType() <<"' from '"<<source.getType()<<"' (source and target type differed)."<<endlog();
00570             return false;
00571         }
00572 
00573         target.setType( source.getType() );
00574 
00575         // Make an updated if present, create if not present
00576         //iterate over source, update or clone PropertyBases
00577 
00578         PropertyBag::Names allnames = source.list();
00579         PropertyBag::Names::const_iterator endnames = std::unique(allnames.begin(), allnames.end());
00580         PropertyBag::Names::const_iterator it( allnames.begin() );
00581         while ( it != endnames )
00582         {
00583             PropertyBag::Properties sources = source.getProperties(*it);
00584             PropertyBag::Properties mines = target.getProperties(*it);
00585             PropertyBag::iterator mit = mines.begin();
00586             for( PropertyBag::const_iterator sit = sources.begin(); sit != sources.end(); ++sit ) {
00587                 if ( mit != mines.end() ) {
00588                     assert( (*sit)->getName() == (*mit)->getName());
00589                     if ( updateOrRefreshProperty( *sit, *mit, true) == false)
00590                         return false;
00591                     // ok.
00592                     ++mit;
00593                 }
00594                 else
00595                     {
00596 #ifndef NDEBUG
00597                         Logger::log() << Logger::Debug;
00598                         Logger::log() << "updateProperties: creating Property "
00599                                       << (*sit)->getType() << " "<< (*sit)->getName()
00600                                       << "." << Logger::endl;
00601 #endif
00602                         // step 1: test for composing a typed property bag:
00603                         PropertyBase* temp = 0;
00604 #if 0
00605                         Property<PropertyBag>* tester = dynamic_cast<Property<PropertyBag>* >(*sit);
00606                         if (tester && tester->value().getType() != "PropertyBag") {
00607                             if (TypeInfo* ti = types::Types()->type(tester->value().getType())) {
00608                                 temp = ti->buildProperty( tester->getName(), tester->getDescription() );
00609                                 assert(temp);
00610                                 bool res = temp->getTypeInfo()->composeType( tester->getDataSource(), temp->getDataSource() );
00611                                 if (!res ) return false;
00612                             }
00613                         }
00614 #endif
00615                         if (!temp) {
00616                             // fallback : clone a new instance (non deep copy)
00617                             temp = (*sit)->create();
00618                             // deep copy clone with original, will never fail.
00619                             temp->update( (*sit) );
00620                         }
00621                         // step 3 : add result to target bag.
00622                         target.add( temp );
00623                     }
00624             }
00625             ++it;
00626         }
00627         return true;
00628     }
00629 
00630     bool updateProperty(PropertyBag& target, const PropertyBag& source, const std::string& name, const std::string& separator)
00631     {
00632         Logger::In in("updateProperty");
00633         // this code has been copied&modified from findProperty().
00634         PropertyBase* source_walker;
00635         PropertyBase* target_walker;
00636         std::string token;
00637         std::string::size_type start = 0;
00638         if ( separator.length() != 0 && name.find(separator) == 0 ) // detect 'root' attribute
00639             start = separator.length();
00640         std::string::size_type len = name.find(separator, start);
00641         if (len != std::string::npos) {
00642             token = name.substr(start,len-start);
00643             start = len + separator.length();      // reset start to next token.
00644             if ( start >= name.length() )
00645                 start = std::string::npos;
00646         }
00647         else {
00648             token = name.substr(start);
00649             start = std::string::npos; // do not look further.
00650         }
00651         source_walker = source.find(token);
00652         target_walker = target.find(token);
00653         if (source_walker != 0 )
00654         {
00655             if ( target_walker == 0 ) {
00656                 // if not present in target, create it !
00657                 target_walker = source_walker->create();
00658                 target.ownProperty( target_walker );
00659             }
00660             Property<PropertyBag>*  source_walker_bag;
00661             Property<PropertyBag>*  target_walker_bag;
00662             source_walker_bag = dynamic_cast<Property<PropertyBag>*>(source_walker);
00663             target_walker_bag = dynamic_cast<Property<PropertyBag>*>(target_walker);
00664             if ( source_walker_bag != 0 && start != std::string::npos ) {
00665                 if ( target_walker_bag == 0 ) {
00666                     log(Error) << "Property '"<<target_walker->getName()<<"' is not a PropertyBag !"<<endlog();
00667                     return false;
00668                 }
00669                 return updateProperty( target_walker_bag->value(), source_walker_bag->rvalue(), name.substr( start ), separator );// a bag so search recursively
00670             }
00671             else {
00672                 // found it, update !
00673                 if (updateOrRefreshProperty( source_walker, target_walker, true) == false)
00674                     return false;
00675                 log(Debug) << "Found Property '"<<target_walker->getName() <<"': update done." << endlog();
00676                 return true;
00677             }
00678         } else {
00679             // error wrong path, not present in source !
00680             log(Error) << "Property '"<< token <<"' is not present in the source PropertyBag !"<<endlog();
00681             return false;
00682         }
00683         // not reached.
00684         return false; // failure
00685     }
00686 
00687     bool refreshProperty(PropertyBag& target, const PropertyBag& source, const std::string& name, const std::string& separator)
00688     {
00689         Logger::In in("refreshProperty");
00690         // this code has been copied&modified from findProperty().
00691         PropertyBase* source_walker;
00692         PropertyBase* target_walker;
00693         std::string token;
00694         std::string::size_type start = 0;
00695         if ( separator.length() != 0 && name.find(separator) == 0 ) // detect 'root' attribute
00696             start = separator.length();
00697         std::string::size_type len = name.find(separator, start);
00698         if (len != std::string::npos) {
00699             token = name.substr(start,len-start);
00700             start = len + separator.length();      // reset start to next token.
00701             if ( start >= name.length() )
00702                 start = std::string::npos;
00703         }
00704         else {
00705             token = name.substr(start);
00706             start = std::string::npos; // do not look further.
00707         }
00708         source_walker = source.find(token);
00709         target_walker = target.find(token);
00710         if (source_walker != 0 )
00711         {
00712             if ( target_walker == 0 ) {
00713                 log(Error) << "Property '"<<source_walker->getName()<<"' was not found in target !"<<endlog();
00714                 return false;
00715             }
00716             Property<PropertyBag>*  source_walker_bag;
00717             Property<PropertyBag>*  target_walker_bag;
00718             source_walker_bag = dynamic_cast<Property<PropertyBag>*>(source_walker);
00719             target_walker_bag = dynamic_cast<Property<PropertyBag>*>(target_walker);
00720             if ( source_walker_bag != 0 && start != std::string::npos ) {
00721                 if ( target_walker_bag == 0 ) {
00722                     log(Error) << "Property '"<<target_walker->getName()<<"' is not a PropertyBag !"<<endlog();
00723                     return false;
00724                 }
00725                 return refreshProperty( target_walker_bag->value(), source_walker_bag->rvalue(), name.substr( start ), separator );// a bag so search recursively
00726             }
00727             else {
00728                 if (updateOrRefreshProperty( source_walker, target_walker, false) == false)
00729                     return false;
00730                 log(Debug) << "Found Property '"<<target_walker->getName() <<"': refresh done." << endlog();
00731                 return true;
00732             }
00733         } else {
00734             // error wrong path, not present in source !
00735             log(Error) << "Property '"<< token <<"' is not present in the source PropertyBag !"<<endlog();
00736             return false;
00737         }
00738         // not reached.
00739         return false; // failure
00740     }
00741 
00742     void deleteProperties(PropertyBag& target)
00743     {
00744         //non-recursive delete.
00745         PropertyBag::const_iterator it( target.getProperties().begin() );
00746         while ( it != target.getProperties().end() )
00747         {
00748             // This loop is solely for deleting not owned properties.
00749             if (!target.ownsProperty( *it ))
00750                 delete (*it);
00751             ++it;
00752         }
00753         target.clear();
00754     }
00755 
00756     void deletePropertyBag(PropertyBag& target)
00757     {
00758         //iterate over target, delete PropertyBases
00759         PropertyBag::const_iterator it( target.getProperties().begin() );
00760         while ( it != target.getProperties().end() )
00761         {
00762             // This loop is solely for deleting not owned properties and recursing
00763             Property<PropertyBag>* result = dynamic_cast< Property<PropertyBag>* >( *it );
00764             if ( result != 0 )
00765                 deletePropertyBag( result->value() );
00766             if (!target.ownsProperty( *it ))
00767                 delete (*it);
00768             ++it;
00769         }
00770         // deletes owned properties.
00771         target.clear();
00772     }
00773 
00774     void flattenPropertyBag(PropertyBag& target, const std::string& separator)
00775     {
00776         //iterate over target, recursively flatten bags.
00777         Property<PropertyBag>* result;
00778         PropertyBag::const_iterator it( target.getProperties().begin() );
00779         while ( it != target.getProperties().end() )
00780         {
00781             result = dynamic_cast< Property<PropertyBag>* >( *it );
00782             if ( result != 0 )
00783             {
00784                 flattenPropertyBag( result->value(), separator );// a bag so flatten recursively
00785                 // copy all elements from result to target.
00786                 PropertyBag::const_iterator flat_it( result->value().getProperties().begin() ) ;
00787                 if ( flat_it != result->value().getProperties().end() )
00788                 {
00789                     while (flat_it != result->value().getProperties().end() )
00790                     {
00791                         (*flat_it)->setName( result->getName() + separator + (*flat_it)->getName() );
00792                         target.add( (*flat_it) );
00793                         result->value().remove( *flat_it );
00794                         flat_it =  result->value().getProperties().begin();
00795                     }
00796                     it = target.getProperties().begin(); // reset iterator
00797                     continue;                            // do not increase it
00798                 }
00799                 // the bag is empty now, but it must stay in target.
00800             }
00801             ++it;
00802         }
00803     }
00804 
00805 }