OpenWalnut  1.4.0
WPropertyGroupBase.cpp
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #include <iostream>
00026 #include <map>
00027 #include <string>
00028 #include <vector>
00029 #include <algorithm>
00030 
00031 #include <boost/tokenizer.hpp>
00032 #include <boost/algorithm/string/predicate.hpp>
00033 
00034 #include "WStringUtils.h"
00035 #include "WLogger.h"
00036 #include "exceptions/WPropertyUnknown.h"
00037 #include "exceptions/WPropertyNotUnique.h"
00038 
00039 #include "WPropertyHelper.h"
00040 
00041 #include "WPropertyGroupBase.h"
00042 
00043 const std::string WPropertyGroupBase::separator = "/";
00044 
00045 WPropertyGroupBase::WPropertyGroupBase( std::string name, std::string description ):
00046     WPropertyBase( name, description ),
00047     m_properties()
00048 {
00049     // this groups update condition also fires upon group modification -> add WSharedObject condition
00050     m_updateCondition->add( m_properties.getChangeCondition() );
00051 }
00052 
00053 WPropertyGroupBase::~WPropertyGroupBase()
00054 {
00055 }
00056 
00057 WPropertyGroupBase::WPropertyGroupBase( const WPropertyGroupBase& from ):
00058     WPropertyBase( from ),
00059     m_properties()
00060 {
00061     // copy the properties inside
00062 
00063     // lock, unlocked if l looses focus
00064     PropertySharedContainerType::ReadTicket l = from.m_properties.getReadTicket();
00065 
00066     // we need to make a deep copy here.
00067     for( PropertyConstIterator iter = l->get().begin(); iter != l->get().end(); ++iter )
00068     {
00069         // clone them to keep dynamic type
00070         addArbitraryProperty( ( *iter )->clone() );
00071     }
00072 
00073     // unlock explicitly
00074     l.reset();
00075 
00076     // this groups update condition also fires upon group modification -> add WSharedObject condition
00077     m_updateCondition->add( m_properties.getChangeCondition() );
00078 }
00079 
00080 bool WPropertyGroupBase::propNamePredicate( boost::shared_ptr< WPropertyBase > prop1, boost::shared_ptr< WPropertyBase > prop2 ) const
00081 {
00082     return ( prop1->getName() == prop2->getName() );
00083 }
00084 
00085 boost::shared_ptr< WPropertyBase > WPropertyGroupBase::findProperty( const WPropertyGroupBase* const props, std::string name ) const
00086 {
00087     boost::shared_ptr< WPropertyBase > result = boost::shared_ptr< WPropertyBase >();
00088 
00089     // lock, unlocked if l looses focus
00090     PropertySharedContainerType::ReadTicket l = props->m_properties.getReadTicket();
00091 
00092     // iterate over the items
00093     for( PropertyContainerType::const_iterator it = l->get().begin(); it != l->get().end(); ++it )
00094     {
00095         if( ( *it )->getName() == name )
00096         {
00097             result = ( *it );
00098             break;
00099         }
00100     }
00101 
00102     // done. Unlocked after l looses focus.
00103     return result;
00104 }
00105 
00106 boost::shared_ptr< WPropertyBase > WPropertyGroupBase::findProperty( std::string name ) const
00107 {
00108     boost::shared_ptr< WPropertyBase > result = boost::shared_ptr< WPropertyBase >();
00109 
00110     // tokenize the name -> contains any paths?
00111     typedef boost::tokenizer<boost::char_separator< char > > tokenizer;
00112     boost::char_separator< char > sep( WPropertyGroupBase::separator.c_str() );   // separate by /
00113     tokenizer tok( name, sep );
00114 
00115     // iterate along the path
00116     const WPropertyGroupBase* curProps = this;       // the group currently in while traversing the path
00117     for( tokenizer::iterator it = tok.begin(); it != tok.end(); ++it )
00118     {
00119         // was the last token not a group?
00120         if( result && !WPVBaseTypes::isPropertyGroup( result->getType() ) )
00121         {
00122             // no it wasn't. This means that one token inside the path is no group, but it needs to be one
00123             return boost::shared_ptr< WPropertyBase >();
00124         }
00125 
00126         // get the properties along the path
00127         result = findProperty( curProps, string_utils::toString( *it ) );
00128         if( !result )
00129         {
00130             // not found? Return NULL.
00131             return boost::shared_ptr< WPropertyBase >();
00132         }
00133         else if( result && WPVBaseTypes::isPropertyGroup( result->getType() ) )
00134         {
00135             // it is a group. Go down
00136             curProps = result->toPropGroupBase().get();
00137         }
00138     }
00139 
00140     return result;
00141 }
00142 
00143 void WPropertyGroupBase::visitAsString( WPropertyGroupBase::PropertyStringVisitor visitor, std::string pathPrefix ) const
00144 {
00145     // read access
00146     PropertySharedContainerType::ReadTicket r = getReadTicket();
00147 
00148     for( PropertyConstIterator it = r->get().begin(); it != r->get().end(); ++it )
00149     {
00150         // path: handle some special cases:
00151         std::string propName = pathPrefix + WPropertyGroupBase::separator + ( *it )->getName();
00152 
00153         // 1: user added a separator
00154         if( boost::algorithm::ends_with( pathPrefix, WPropertyGroupBase::separator ) )
00155         {
00156             propName = pathPrefix + ( *it )->getName();
00157         }
00158         // 2: avoid separator if prefix is empty
00159         if( pathPrefix.empty() )
00160         {
00161             propName = ( *it )->getName();
00162         }
00163 
00164         // is it a group type?
00165         WPropertyGroupBase::SPtr g = ( *it )->toPropGroupBase();
00166         if( g )
00167         {
00168             // recurse down
00169             g->visitAsString( visitor, propName );
00170         }
00171         else
00172         {
00173             // it is a leaf, call visitor
00174             std::string value = ( *it )->getAsString();
00175             visitor( propName, value );
00176         }
00177     }
00178 }
00179 
00180 bool WPropertyGroupBase::existsProperty( std::string name )
00181 {
00182     return ( findProperty( name ) != boost::shared_ptr< WPropertyBase >() );
00183 }
00184 
00185 boost::shared_ptr< WPropertyBase > WPropertyGroupBase::getProperty( std::string name )
00186 {
00187     boost::shared_ptr< WPropertyBase > p = findProperty( name );
00188     if( p == boost::shared_ptr< WPropertyBase >() )
00189     {
00190         throw WPropertyUnknown( std::string( "Property \"" + name + "\" can't be found." ) );
00191     }
00192 
00193     return p;
00194 }
00195 
00196 void WPropertyGroupBase::addArbitraryProperty( WPropertyBase::SPtr prop )
00197 {
00198     // lock, unlocked if l looses focus
00199     PropertySharedContainerType::WriteTicket l = m_properties.getWriteTicket();
00200 
00201     // NOTE: WPropertyBase already prohibits invalid property names -> no check needed here
00202 
00203     // check uniqueness:
00204     if( std::count_if( l->get().begin(), l->get().end(),
00205             boost::bind( boost::mem_fn( &WPropertyGroupBase::propNamePredicate ), this, prop, _1 ) ) )
00206     {
00207         // unlock explicitly
00208         l.reset();
00209 
00210         // oh oh, this property name is not unique in this group
00211         if( !getName().empty() )
00212         {
00213             throw WPropertyNotUnique( std::string( "Property \"" + prop->getName() + "\" is not unique in this group (\"" + getName() + "\")." ) );
00214         }
00215         else
00216         {
00217             throw WPropertyNotUnique( std::string( "Property \"" + prop->getName() + "\" is not unique in this group (unnamed root)." ) );
00218         }
00219     }
00220 
00221     // PV_PURPOSE_INFORMATION groups do not allow PV_PURPOSE_PARAMETER properties but vice versa.
00222     if( getPurpose() == PV_PURPOSE_INFORMATION )
00223     {
00224         prop->setPurpose( PV_PURPOSE_INFORMATION );
00225     }
00226     // INFORMATION properties are allowed inside PARAMETER groups -> do not set the properties purpose.
00227 
00228     l->get().push_back( prop );
00229 
00230     // add the child's update condition to the list
00231     m_updateCondition->add( prop->getUpdateCondition() );
00232 }
00233 
00234 WPropertyGroupBase::PropertySharedContainerType::ReadTicket WPropertyGroupBase::getProperties() const
00235 {
00236     return m_properties.getReadTicket();
00237 }
00238 
00239 WPropertyGroupBase::PropertySharedContainerType::ReadTicket WPropertyGroupBase::getReadTicket() const
00240 {
00241     return m_properties.getReadTicket();
00242 }
00243