Properties.h
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5  *
6  * ArmarX is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * ArmarX is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * \package ArmarXCore::core
19  * \author Jan Issac (jan dot issac at gmx dot de)
20  * \date 2012
21  * \copyright http://www.gnu.org/licenses/gpl-2.0.txt
22  * GNU General Public License
23  */
24 
25 #pragma once
26 
27 #include "Property.h"
28 #include "PropertyUser.h"
30 #include "PropertyDefinition.h"
41 
42 /**
43 \defgroup properties Properties
44 \ingroup DistributedProcessingGrp core-utility
45 \copydoc PropertiesDoc
46 
47 \page PropertiesDoc Properties
48 \tableofcontents
49 \section introduction Introduction
50 
51 ArmarX properties are the tool in the ArmarX framework to retrieve Ice
52 configuration properties and command line options. This tool is part of
53 the framework core and can be considered as an extension to the plain
54 Ice::Properties container. As for ArmarXCore the properties are
55 integrated in armarx::Component and armarx::Application. Both implement the
56 armarx::PropertyUser interface and offer direct access to the properties
57 within their scope.
58 
59 \note We refer to configuration variables defined in a config file as
60  \em properties and configuration variables passed though command line
61  as \em options
62 
63 \section features Feature overview
64 
65 As mentioned before, the ArmarX properties extend the Ice::Properties by
66 several capabilities:
67 
68 - Mapping config values onto objects of any desired type
69 - Validating config values using regular expressions
70 - Forcing required properties to be set
71 - Returning defaults for optional properties regarless the default object
72  type
73 - Setting bounds for numeric properties and options
74 - Forcing case sensitivity on config values
75 - Generating formatted and detailed description of properties for
76 - Help output
77 - User manual documentation (e.g. Doxygen, Latex, HTML, etc)
78 - Config files automatically filled with default values (e.g. Ice.Config
79  and XML files)
80 
81 \section propertiesOverview Structure overview
82 
83 \image html CompactPropertiesOverview.png
84 
85 \subsection propertyuser armarx::PropertyUser
86 
87 Every component (in general manner) which aims to provide properties has
88 to implement the armarx::PropertyUser interface.
89 
90 armarx::PropertyUser basic outline
91 \code
92 class PropertyUser
93 {
94 public:
95  template <typename Type> Property<Type> getProperty(string name);
96  virtual PropertyDefinitionsPtr createPropertyDefinitions() = 0;
97 };
98 \endcode
99 
100 As can be seen, the armarx::PropertyUser::createPropertyDefinitions() factory
101 function has to be implemented. It creates an instance of the property
102 definitions.
103 
104 The armarx::PropertyUser::getProperty() function provides access to a desired
105 property as long as it is defined.
106 
107 \subsection propertydefinition armarx::PropertyDefinitionContainer
108 
109 armarx::PropertyDefinitionContainer basic outline
110 \code
111 class PropertyDefinitionContainer
112 {
113 public:
114  PropertyDefinitionContainer(std::string prefix);
115 
116  template <typename PropertyType>
117  PropertyDefinition<PropertyType>& defineRequiredProperty(
118  string name,
119  string description);
120 
121  template <typename PropertyType>
122  PropertyDefinition<PropertyType>& defineOptionalProperty(
123  string name,
124  PropertyType defaultValue,
125  string description);
126 
127  template <typename PropertyType>
128  PropertyDefinition<PropertyType>& getDefintion(string name);
129 
130  string toString(PropertyDefinitionFormatter& formatter);
131 };
132 \endcode
133 
134 This is the class you will extend to define your own properties.
135 
136 The constructor takes a prefix as an argument. Using this prefix, you can
137 specify the namespace (e.g. Domain, Component name, Application name) your
138 properties belong to.
139 
140 E.g. if the prefix is "ArmarX.MyComponent", then the PropertyUser
141 will select all properties which start with "ArmarX.MyComponent." (Note
142 the trailing dot!). A full property name is then
143 "ArmarX.MyComponent.myFrameRate".
144 
145 To define a property you may use one of the following functions:
146 - defineRequiredProperty()
147 - defineOptionalProperty()
148 
149 Both functions return an armarx::PropertyDefinition instance. This is
150 convenient to set the definition attributes immediately as shown below:
151 \code
152 class MyDefinitions:
153  public PropertyDefinitionContainer
154 {
155 public:
156  MyDefinitions(string prefix):
157  PropertyDefinitionContainer(prefix)
158  {
159 
160  defineOptionalProperty("FrameRate", 30.f, "Frames per second")
161  .setMin(1.f)
162  .setMax(60.f)
163  .setMatchRegex("\\d+(.\\d*)?");
164  }
165 };
166 \endcode
167 
168 
169 \section Features
170 
171 \li Fluent interface
172 \li Generic property type mapping
173 \li Property requirement check
174 \li Property value mapping validation
175 \li Property value validation by regular expression matching
176 \li Property min. & max. value limitation for numeric values
177 \li Supports case sensitive and case insensitive value mapping
178 \li Case sensitivity can be changed at any point without reinitializing the mapper
179 \li Default value fallback on value retrieval errors
180 
181 A more detailed description of each feature follows:
182 
183 \subsection properties-fluent Fluent interface
184 The Fluent Interface is defined by the set of functions stated above
185 in the outline. These functions preserve the context (the function
186 call on the object is self-referential) and therefore can be chained.
187 This improves the readability and allows the use of Property
188 without declaring a named instance for each property. The following
189 examples illustrate this:
190 
191 \code
192 enum BayerPatternType
193 {
194  eBayerPatternBg,
195  eBayerPatternGb,
196  eBayerPatternGr,
197  eBayerPatternRg
198 };
199 \endcode
200 
201 \subsubsection properties-nofluentinterface Using the mapper without fluent interface
202 
203 \code
204  Property<BayerPatternType> bayerPatternTypeProp("VisionX.Capturer.BayerPatternType", properties, eBayerPatternRg);
205 
206  bayerPatternTypeProp.setCaseInsensitive(true);
207  bayerPatternTypeProp.map("bayer-pattern-bg", eBayerPatternBg);
208  bayerPatternTypeProp.map("bayer-pattern-gb", eBayerPatternGb);
209  bayerPatternTypeProp.map("bayer-pattern-gr", eBayerPatternGr);
210  bayerPatternTypeProp.map("bayer-pattern-rg", eBayerPatternRg);
211 
212  BayerPatternType bayerPatternType = bayerPatternTypeProp.getValue();
213 \endcode
214 
215 
216 \subsubsection properties-fluentinterface Using the mapper with fluent interface
217 
218 \code
219  BayerPatternType bayerPatternType = Property<BayerPatternType>("VisionX.Capturer.BayerPatternType", properties, eBayerPatternRg)
220  .map("bayer-pattern-bg", eBayerPatternBg)
221  .map("bayer-pattern-gb", eBayerPatternGb)
222  .map("bayer-pattern-gr", eBayerPatternGr)
223  .map("bayer-pattern-rg", eBayerPatternRg)
224  .setCaseInsensitive(true)
225  .getValue();
226 \endcode
227 
228 The method chaining can be terminated at any time. Thus, using the
229 fluent interface is optional as shown by the previous examples.
230 
231 
232 \subsection properties-GenericMapping Generic property type mapping
233 
234 The Ice::Properties support only string and integer return values
235 without any validation, whereas the armarx::Property is able to
236 return any type you specify for the typename \b PropertyType.
237 The mapping of strings onto PropertyType values is done by means
238 of <b>map(string valueString, PropertyType value)</b>. The following
239 examples maps string words onto boolean values:
240 
241 \code
242  bool usingFormat7Mode = Property<bool>("VisionX.Capturer.Format7Mode", properties, false)
243  .map("true", true)
244  .map("yes", true)
245  .map("1", true)
246  .map("false", false)
247  .map("no", false)
248  .map("0", false)
249  .getValue();
250 \endcode
251 
252 
253 Sometimes you only need to convert a string into a numeric value
254 or even want to get the raw string itself. The return value type
255 depends on which value retrieval function you use. These come in
256 three types:
257 
258 1. \em typename \b PropertyType requires mapping and is accessible by the following functions:
259  \code PropertyType getValue() \endcode
260  - It's specified in the template parameter: Property<\b PropertyType> (e.g. Property<float>(...))
261  - Returns one of the mapped values of the type \em PropertyType you specified
262  - Throws a MissingRequiredPropertyException if the property is not defined and set as required
263  - Throws a UnmappedValueException if value is not mapped.
264  - Throws a InvalidPropertyValueException if the syntax of the value is incorrect.
265 
266  \code PropertyType getValueOrDefault() \endcode
267  - Returns one of the mapped values of the type \em PropertyType you specified
268  - Never throws. If the value is not mapped, the default value specified in constructor will be returned.
269 
270 
271 2. \em typename \b NumericType requires no mapping, performs a lexical cast and is accessible by the following functions:
272 \code NumericType getNumericValue<NumericType>() \endcode
273  - It's specified in the \em getNumericValue function template parameter (e.g. float frameRate = myMapper.getNumericValue<\b float>()).
274  - Returns a numeric value of the type \em NumericType if possible
275  - Throws a MissingRequiredPropertyException if the property is not defined and set as required
276  - Throws a ValueRangeExceededException if value exceeds the bounds
277  - Throws a InvalidPropertyValueException if the syntax of the value is incorrect.
278 
279 \code NumericType getNumericValueOrDefault<NumericType>() \endcode
280  - Returns a numeric value of the type ''NumericType'' if possible
281  - Never throws. If the value not available, the default value specified in constructor will be returned.
282 
283 3. \b std::string raw string property value. Requires no mapping and is accessible by the following functions:
284 \code std::string getRawStringValue(); \endcode
285  - Returns the raw string of the value similarly to properties->getProperty("MyProperty") but checks the syntax of the value if required
286  - Throws a MissingRequiredPropertyException if the property is not defined and set as required
287  - Throws a InvalidPropertyValueException if the syntax of the value is incorrect.
288 
289  \code std::string getRawStringValue(std::string default); \endcode
290  - Returns the raw string of the value similarly to properties->getProperty("MyProperty") but checks the syntax of the value if required
291  - Never throws. If the value is not available, the passed default value will be returned.
292 
293 
294 As you may have noticed, for each of the three value types there
295 are two functions. One that throws error specific exceptions and
296 one that never throws. Instead it returns a default value on errors.
297 It is up to the developer which one of the functions shall be used.
298 
299 
300 \subsection properties-check Property requirement check
301 In few cases a component may require configuration values in order
302 to proceed, assuming no default value is known at compile time.
303 To assert that a certain property value has been defined you may
304 tell the mapper that the property is required.
305 If the property is not set, an exception is thrown while trying
306 to get the value from the mapper (e.g. by calling getValue()):
307 \code
308  try
309  {
310  std::string uidStr = Property<std::string>("VisionX.Capturer.CameraUIDs", properties, "")
311  .setRequired(true)
312  .getRawStringValue();
313  }
314  catch(const armarx::exceptions::local::MissingRequiredPropertyException &exp)
315  {
316  std::cout << "Cannot run without Camera UIDs. Terminating ..." << std::endl;
317  exit(1);
318  }
319 \endcode
320 
321 
322 \subsection properties-Validation Property value mapping validation
323 The \em getValue() function will throw an armarx::exceptions::local::UnmappedValueException
324 if the property value is not mapped. The following examples shows this case:
325  \code
326  // config file
327  ...
328  VisionX.Capturer.Format7Mode = yes
329  ...
330  \endcode
331  \code
332  // component
333  ...
334  bool usingFormat7Mode = Property<bool>("VisionX.Capturer.Format7Mode", properties, false)
335  .map("1", true)
336  .map("0", false)
337  .getValue();
338  ...
339 \endcode
340 
341 Since the word "yes" is not mapped, an exception is thrown. If you want
342 to avoid the exception you may use the \em getValueOrDefault() function
343 which will return the default value specified in the constructor instead
344 of throwing an exception.
345 
346 
347 \subsection properties-validation-regexp Property value validation by regular expression matching
348 
349 It's in many cases easier to parse and interpret values if they match a
350 certain pattern. For example assume we need two camera UIDs to initialize
351 the stereo capturer. Each UID must have a length of 16 characters and
352 consist solely of numbers and the letters A-F and finally the UIDs
353 should be separated only by a comma or whitespace. At this point regular
354 expressions come in handy to assert this pattern:
355 
356 \code
357  // Camera UIDs
358  std::string uidStr = Property<std::string>(propPrefix + ".CameraUIDs", properties, "")
359  .setRequired(true)
360  .setMatchRegex("\\s*[a-zA-Z0-9]{16}\\s*((,|\\s)\\s*[a-zA-Z0-9]{16})")
361  .getRawStringValue();
362 \endcode
363 
364 \subsection properties-Numeric Numeric property values and the min. & max. value limitation
365 The Property supports simple lexical cast for numeric values. If
366 the cast failes due to wrong numeric syntax, an armarx::exceptions::local::InvalidPropertyValueException
367 is thrown. Numeric value boundaries may be defined by the functions
368 \b setMin() and \b setMax(). The bounds are asstered when using the
369 \em getNumericValue().
370 If the property value is out of bounds, the armarx::exceptions::local::ValueRangeExceededException
371 will be thrown. Again, the exceptions can be avoided by using the
372 getNumericValueOrDefault() instead.
373 
374 
375 \subsection properties-case-sensitivity Support of case sensitive and case insensitive value mapping
376 \code
377  bool usingFormat7Mode = Property<bool>("VisionX.Capturer.Format7Mode", properties, false)
378  .setCaseInsensitive(true)
379  .map("yes", true)
380  .map("no", false)
381  .getValue();
382 \endcode
383 
384 The mapper in the example above would map the words "Yes" and "YES" onto
385 true as well, since it acts case-insensitive. This avoids many tedious
386 mapping and permitting less restrictive inputs. The setCaseInsensitive(bool)
387 function can be called at any time during the mapping.
388 */
389 
PropertyDefinitionXmlFormatter.h
PropertyDefinitionContainerFormatter.h
PropertyDefinitionDoxygenFormatter.h
PropertyDefinitionFormatter.h
PropertyDefinitionHelpFormatter.h
PropertyDefinitionInterface.h
Property.h
PropertyUser.h
PropertyDefinitionConfigFormatter.h
PropertyDefinitionBriefHelpFormatter.h
PropertyDefinitionDoxygenComponentPagesFormatter.h
PropertyDefinitionContainer.h
PropertyDefinitionContainerBriefHelpFormatter.h
PropertyDefinition.h