OpenWalnut  1.4.0
WPropertyGroupBase.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <iostream>
26 #include <map>
27 #include <string>
28 #include <vector>
29 #include <algorithm>
30 
31 #include <boost/tokenizer.hpp>
32 #include <boost/algorithm/string/predicate.hpp>
33 
34 #include "WStringUtils.h"
35 #include "WLogger.h"
36 #include "exceptions/WPropertyUnknown.h"
37 #include "exceptions/WPropertyNotUnique.h"
38 
39 #include "WPropertyHelper.h"
40 
41 #include "WPropertyGroupBase.h"
42 
43 const std::string WPropertyGroupBase::separator = "/";
44 
45 WPropertyGroupBase::WPropertyGroupBase( std::string name, std::string description ):
46  WPropertyBase( name, description ),
47  m_properties()
48 {
49  // this groups update condition also fires upon group modification -> add WSharedObject condition
51 }
52 
54 {
55 }
56 
58  WPropertyBase( from ),
59  m_properties()
60 {
61  // copy the properties inside
62 
63  // lock, unlocked if l looses focus
65 
66  // we need to make a deep copy here.
67  for( PropertyConstIterator iter = l->get().begin(); iter != l->get().end(); ++iter )
68  {
69  // clone them to keep dynamic type
70  addArbitraryProperty( ( *iter )->clone() );
71  }
72 
73  // unlock explicitly
74  l.reset();
75 
76  // this groups update condition also fires upon group modification -> add WSharedObject condition
78 }
79 
80 bool WPropertyGroupBase::propNamePredicate( boost::shared_ptr< WPropertyBase > prop1, boost::shared_ptr< WPropertyBase > prop2 ) const
81 {
82  return ( prop1->getName() == prop2->getName() );
83 }
84 
85 boost::shared_ptr< WPropertyBase > WPropertyGroupBase::findProperty( const WPropertyGroupBase* const props, std::string name ) const
86 {
87  boost::shared_ptr< WPropertyBase > result = boost::shared_ptr< WPropertyBase >();
88 
89  // lock, unlocked if l looses focus
91 
92  // iterate over the items
93  for( PropertyContainerType::const_iterator it = l->get().begin(); it != l->get().end(); ++it )
94  {
95  if( ( *it )->getName() == name )
96  {
97  result = ( *it );
98  break;
99  }
100  }
101 
102  // done. Unlocked after l looses focus.
103  return result;
104 }
105 
106 boost::shared_ptr< WPropertyBase > WPropertyGroupBase::findProperty( std::string name ) const
107 {
108  boost::shared_ptr< WPropertyBase > result = boost::shared_ptr< WPropertyBase >();
109 
110  // tokenize the name -> contains any paths?
111  typedef boost::tokenizer<boost::char_separator< char > > tokenizer;
112  boost::char_separator< char > sep( WPropertyGroupBase::separator.c_str() ); // separate by /
113  tokenizer tok( name, sep );
114 
115  // iterate along the path
116  const WPropertyGroupBase* curProps = this; // the group currently in while traversing the path
117  for( tokenizer::iterator it = tok.begin(); it != tok.end(); ++it )
118  {
119  // was the last token not a group?
120  if( result && !WPVBaseTypes::isPropertyGroup( result->getType() ) )
121  {
122  // no it wasn't. This means that one token inside the path is no group, but it needs to be one
123  return boost::shared_ptr< WPropertyBase >();
124  }
125 
126  // get the properties along the path
127  result = findProperty( curProps, string_utils::toString( *it ) );
128  if( !result )
129  {
130  // not found? Return NULL.
131  return boost::shared_ptr< WPropertyBase >();
132  }
133  else if( result && WPVBaseTypes::isPropertyGroup( result->getType() ) )
134  {
135  // it is a group. Go down
136  curProps = result->toPropGroupBase().get();
137  }
138  }
139 
140  return result;
141 }
142 
144 {
145  // read access
147 
148  for( PropertyConstIterator it = r->get().begin(); it != r->get().end(); ++it )
149  {
150  // path: handle some special cases:
151  std::string propName = pathPrefix + WPropertyGroupBase::separator + ( *it )->getName();
152 
153  // 1: user added a separator
154  if( boost::algorithm::ends_with( pathPrefix, WPropertyGroupBase::separator ) )
155  {
156  propName = pathPrefix + ( *it )->getName();
157  }
158  // 2: avoid separator if prefix is empty
159  if( pathPrefix.empty() )
160  {
161  propName = ( *it )->getName();
162  }
163 
164  // is it a group type?
165  WPropertyGroupBase::SPtr g = ( *it )->toPropGroupBase();
166  if( g )
167  {
168  // recurse down
169  g->visitAsString( visitor, propName );
170  }
171  else
172  {
173  // it is a leaf, call visitor
174  std::string value = ( *it )->getAsString();
175  visitor( propName, value );
176  }
177  }
178 }
179 
180 bool WPropertyGroupBase::existsProperty( std::string name )
181 {
182  return ( findProperty( name ) != boost::shared_ptr< WPropertyBase >() );
183 }
184 
185 boost::shared_ptr< WPropertyBase > WPropertyGroupBase::getProperty( std::string name )
186 {
187  boost::shared_ptr< WPropertyBase > p = findProperty( name );
188  if( p == boost::shared_ptr< WPropertyBase >() )
189  {
190  throw WPropertyUnknown( std::string( "Property \"" + name + "\" can't be found." ) );
191  }
192 
193  return p;
194 }
195 
197 {
198  // lock, unlocked if l looses focus
200 
201  // NOTE: WPropertyBase already prohibits invalid property names -> no check needed here
202 
203  // check uniqueness:
204  if( std::count_if( l->get().begin(), l->get().end(),
205  boost::bind( boost::mem_fn( &WPropertyGroupBase::propNamePredicate ), this, prop, _1 ) ) )
206  {
207  // unlock explicitly
208  l.reset();
209 
210  // oh oh, this property name is not unique in this group
211  if( !getName().empty() )
212  {
213  throw WPropertyNotUnique( std::string( "Property \"" + prop->getName() + "\" is not unique in this group (\"" + getName() + "\")." ) );
214  }
215  else
216  {
217  throw WPropertyNotUnique( std::string( "Property \"" + prop->getName() + "\" is not unique in this group (unnamed root)." ) );
218  }
219  }
220 
221  // PV_PURPOSE_INFORMATION groups do not allow PV_PURPOSE_PARAMETER properties but vice versa.
222  if( getPurpose() == PV_PURPOSE_INFORMATION )
223  {
224  prop->setPurpose( PV_PURPOSE_INFORMATION );
225  }
226  // INFORMATION properties are allowed inside PARAMETER groups -> do not set the properties purpose.
227 
228  l->get().push_back( prop );
229 
230  // add the child's update condition to the list
231  m_updateCondition->add( prop->getUpdateCondition() );
232 }
233 
235 {
236  return m_properties.getReadTicket();
237 }
238 
240 {
241  return m_properties.getReadTicket();
242 }
243 
bool propNamePredicate(boost::shared_ptr< WPropertyBase > prop1, boost::shared_ptr< WPropertyBase > prop2) const
Compares the names of two properties and returns true if they are equal.
boost::shared_ptr< WSharedObjectTicketWrite< PropertyContainerType > > WriteTicket
Type for write tickets.
Definition: WSharedObject.h:67
boost::shared_ptr< WPropertyGroupBase > SPtr
Convenience typedef for a boost::shared_ptr< WPropertyGroupBase >.
boost::function< void(std::string, std::string)> PropertyStringVisitor
The visitor type used to visit properties as strings.
virtual void visitAsString(PropertyStringVisitor visitor, std::string pathPrefix="") const
Visit all leafs in the property three that aren't empty groups.
PropertySharedContainerType m_properties
The set of proerties.
ReadTicket getReadTicket() const
Returns a ticket to get read access to the contained data.
WriteTicket getWriteTicket(bool suppressNotify=false) const
Returns a ticket to get write access to the contained data.
void addArbitraryProperty(WPropertyBase::SPtr prop)
Insert the specified property into the list.
boost::shared_ptr< WConditionSet > m_updateCondition
Condition notified whenever something changes.
boost::shared_ptr< WPropertyGroupBase > toPropGroupBase()
Convert the property to a WPropertyGroupBase.
virtual PROPERTY_PURPOSE getPurpose() const
Gets the purpose of a property.
virtual PropertySharedContainerType::ReadTicket getProperties() const
Returns a read ticket for read-access to the list of properties.
bool isPropertyGroup(PROPERTY_TYPE type)
Checks which property types are derived from WPropertyGroupBase.
virtual bool existsProperty(std::string name)
Helper function that finds a property by its name.
This is the base class and interface for property groups.
std::string toString(const T &value)
Convert a given value to a string.
Definition: WStringUtils.h:120
Abstract base class for all properties.
Definition: WPropertyBase.h:44
WPropertyGroupBase(std::string name, std::string description)
Constructor.
Indicates that a given property is not unique in a group of properties.
boost::shared_ptr< WPropertyBase > SPtr
Convenience typedef for a boost::shared_ptr< WPropertyBase >
Definition: WPropertyBase.h:50
static const std::string separator
The separator used to separate groups and subgroups.
virtual boost::shared_ptr< WPropertyBase > findProperty(std::string name) const
Searches the property with a given name.
virtual boost::shared_ptr< WPropertyBase > getProperty(std::string name)
Function searches the property.
std::string getName() const
Gets the name of the class.
PropertyContainerType::const_iterator PropertyConstIterator
The const iterator type of the container.
virtual PropertySharedContainerType::ReadTicket getReadTicket() const
Returns an read ticket for the properties.
boost::shared_ptr< WSharedObjectTicketRead< PropertyContainerType > > ReadTicket
Type for read tickets.
Definition: WSharedObject.h:62
virtual ~WPropertyGroupBase()
Destructor.
boost::shared_ptr< WCondition > getChangeCondition() const
This condition fires whenever the encapsulated object changed.
Indicates invalid element access of a container.