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 "PropertyDefinition.h"
40#include "PropertyUser.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
51ArmarX properties are the tool in the ArmarX framework to retrieve Ice
52configuration properties and command line options. This tool is part of
53the framework core and can be considered as an extension to the plain
54Ice::Properties container. As for ArmarXCore the properties are
55integrated in armarx::Component and armarx::Application. Both implement the
56armarx::PropertyUser interface and offer direct access to the properties
57within 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
65As mentioned before, the ArmarX properties extend the Ice::Properties by
66several 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
87Every component (in general manner) which aims to provide properties has
88to implement the armarx::PropertyUser interface.
89
90armarx::PropertyUser basic outline
91\code
92class PropertyUser
93{
94public:
95 template <typename Type> Property<Type> getProperty(string name);
96 virtual PropertyDefinitionsPtr createPropertyDefinitions() = 0;
97};
98\endcode
99
100As can be seen, the armarx::PropertyUser::createPropertyDefinitions() factory
101function has to be implemented. It creates an instance of the property
102definitions.
103
104The armarx::PropertyUser::getProperty() function provides access to a desired
105property as long as it is defined.
106
107\subsection propertydefinition armarx::PropertyDefinitionContainer
108
109armarx::PropertyDefinitionContainer basic outline
110\code
111class PropertyDefinitionContainer
112{
113public:
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
134This is the class you will extend to define your own properties.
135
136The constructor takes a prefix as an argument. Using this prefix, you can
137specify the namespace (e.g. Domain, Component name, Application name) your
138properties belong to.
139
140E.g. if the prefix is "ArmarX.MyComponent", then the PropertyUser
141will select all properties which start with "ArmarX.MyComponent." (Note
142the trailing dot!). A full property name is then
143"ArmarX.MyComponent.myFrameRate".
144
145To define a property you may use one of the following functions:
146- defineRequiredProperty()
147- defineOptionalProperty()
148
149Both functions return an armarx::PropertyDefinition instance. This is
150convenient to set the definition attributes immediately as shown below:
151\code
152class MyDefinitions:
153 public PropertyDefinitionContainer
154{
155public:
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
181A more detailed description of each feature follows:
182
183\subsection properties-fluent Fluent interface
184The Fluent Interface is defined by the set of functions stated above
185in the outline. These functions preserve the context (the function
186call on the object is self-referential) and therefore can be chained.
187This improves the readability and allows the use of Property
188without declaring a named instance for each property. The following
189examples illustrate this:
190
191\code
192enum 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
228The method chaining can be terminated at any time. Thus, using the
229fluent interface is optional as shown by the previous examples.
230
231
232\subsection properties-GenericMapping Generic property type mapping
233
234The Ice::Properties support only string and integer return values
235without any validation, whereas the armarx::Property is able to
236return any type you specify for the typename \b PropertyType.
237The mapping of strings onto PropertyType values is done by means
238of <b>map(string valueString, PropertyType value)</b>. The following
239examples 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
253Sometimes you only need to convert a string into a numeric value
254or even want to get the raw string itself. The return value type
255depends on which value retrieval function you use. These come in
256three types:
257
2581. \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
2712. \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
2833. \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
294As you may have noticed, for each of the three value types there
295are two functions. One that throws error specific exceptions and
296one that never throws. Instead it returns a default value on errors.
297It is up to the developer which one of the functions shall be used.
298
299
300\subsection properties-check Property requirement check
301In few cases a component may require configuration values in order
302to proceed, assuming no default value is known at compile time.
303To assert that a certain property value has been defined you may
304tell the mapper that the property is required.
305If the property is not set, an exception is thrown while trying
306to 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
323The \em getValue() function will throw an armarx::exceptions::local::UnmappedValueException
324if 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
341Since the word "yes" is not mapped, an exception is thrown. If you want
342to avoid the exception you may use the \em getValueOrDefault() function
343which will return the default value specified in the constructor instead
344of throwing an exception.
345
346
347\subsection properties-validation-regexp Property value validation by regular expression matching
348
349It's in many cases easier to parse and interpret values if they match a
350certain pattern. For example assume we need two camera UIDs to initialize
351the stereo capturer. Each UID must have a length of 16 characters and
352consist solely of numbers and the letters A-F and finally the UIDs
353should be separated only by a comma or whitespace. At this point regular
354expressions 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
365The Property supports simple lexical cast for numeric values. If
366the cast failes due to wrong numeric syntax, an armarx::exceptions::local::InvalidPropertyValueException
367is 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().
370If the property value is out of bounds, the armarx::exceptions::local::ValueRangeExceededException
371will be thrown. Again, the exceptions can be avoided by using the
372getNumericValueOrDefault() 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
384The mapper in the example above would map the words "Yes" and "YES" onto
385true as well, since it acts case-insensitive. This avoids many tedious
386mapping and permitting less restrictive inputs. The setCaseInsensitive(bool)
387function can be called at any time during the mapping.
388*/