Classes

class  IceProperties
 IceProperties stores ice properties and resolves property inheritance. More...
 
class  Property< PropertyType >
 Provides access to Ice properties with extended capabilities. More...
 
class  PropertyDefinition< PropertyType >
 PropertyDefinition defines a property that will be available within the PropertyUser. More...
 
class  PropertyDefinitionBase
 Common interface of any property definition. More...
 
class  PropertyDefinitionBriefHelpFormatter
 PropertyDefinitionBriefHelpFormatter. More...
 
class  PropertyDefinitionConfigFormatter
 PropertyDefinitionConfigFormatter. More...
 
class  PropertyDefinitionContainer
 PropertyDefinitionContainer. More...
 
class  PropertyDefinitionContainerBriefHelpFormatter
 PropertyDefinitionContainerBriefHelpFormatter. More...
 
class  PropertyDefinitionContainerFormatter
 PropertyDefinitionContainerFormatter. More...
 
class  PropertyDefinitionDoxygenComponentPagesFormatter
 PropertyDefinitionDoxygenComponentPagesFormatter creates doxygen output with an own group for every component. More...
 
class  PropertyDefinitionDoxygenFormatter
 PropertyDefinitionDoxygenFormatter creates doxygen output. More...
 
class  PropertyDefinitionFormatter
 PropertyDefinitionFormatter is the base class for all formatters of PropertyDefinitions. More...
 
class  PropertyDefinitionHelpFormatter
 PropertyDefinitionHelpFormatter. More...
 
class  PropertyDefinitionXmlFormatter
 PropertyDefinitionXmlFormatter. More...
 

Detailed Description

Introduction

ArmarX properties are the tool in the ArmarX framework to retrieve Ice configuration properties and command line options. This tool is part of the framework core and can be considered as an extension to the plain Ice::Properties container. As for ArmarXCore the properties are integrated in armarx::Component and armarx::Application. Both implement the armarx::PropertyUser interface and offer direct access to the properties within their scope.

Note
We refer to configuration variables defined in a config file as properties and configuration variables passed though command line as options

Feature overview

As mentioned before, the ArmarX properties extend the Ice::Properties by several capabilities:

Structure overview

armarx::PropertyUser

Every component (in general manner) which aims to provide properties has to implement the armarx::PropertyUser interface.

armarx::PropertyUser basic outline

class PropertyUser
{
public:
template <typename Type> Property<Type> getProperty(string name);
virtual PropertyDefinitionsPtr createPropertyDefinitions() = 0;
};

As can be seen, the armarx::PropertyUser::createPropertyDefinitions() factory function has to be implemented. It creates an instance of the property definitions.

The armarx::PropertyUser::getProperty() function provides access to a desired property as long as it is defined.

armarx::PropertyDefinitionContainer

armarx::PropertyDefinitionContainer basic outline

class PropertyDefinitionContainer
{
public:
PropertyDefinitionContainer(std::string prefix);
template <typename PropertyType>
PropertyDefinition<PropertyType>& defineRequiredProperty(
string name,
string description);
template <typename PropertyType>
PropertyDefinition<PropertyType>& defineOptionalProperty(
string name,
PropertyType defaultValue,
string description);
template <typename PropertyType>
PropertyDefinition<PropertyType>& getDefintion(string name);
string toString(PropertyDefinitionFormatter& formatter);
};

This is the class you will extend to define your own properties.

The constructor takes a prefix as an argument. Using this prefix, you can specify the namespace (e.g. Domain, Component name, Application name) your properties belong to.

E.g. if the prefix is "ArmarX.MyComponent", then the PropertyUser will select all properties which start with "ArmarX.MyComponent." (Note the trailing dot!). A full property name is then "ArmarX.MyComponent.myFrameRate".

To define a property you may use one of the following functions:

Both functions return an armarx::PropertyDefinition instance. This is convenient to set the definition attributes immediately as shown below:

class MyDefinitions:
public PropertyDefinitionContainer
{
public:
MyDefinitions(string prefix):
PropertyDefinitionContainer(prefix)
{
defineOptionalProperty("FrameRate", 30.f, "Frames per second")
.setMin(1.f)
.setMax(60.f)
.setMatchRegex("\\d+(.\\d*)?");
}
};

Features

A more detailed description of each feature follows:

Fluent interface

The Fluent Interface is defined by the set of functions stated above in the outline. These functions preserve the context (the function call on the object is self-referential) and therefore can be chained. This improves the readability and allows the use of Property without declaring a named instance for each property. The following examples illustrate this:

enum BayerPatternType
{
eBayerPatternBg,
eBayerPatternGb,
eBayerPatternGr,
eBayerPatternRg
};

Using the mapper without fluent interface

Property<BayerPatternType> bayerPatternTypeProp("VisionX.Capturer.BayerPatternType", properties, eBayerPatternRg);
bayerPatternTypeProp.setCaseInsensitive(true);
bayerPatternTypeProp.map("bayer-pattern-bg", eBayerPatternBg);
bayerPatternTypeProp.map("bayer-pattern-gb", eBayerPatternGb);
bayerPatternTypeProp.map("bayer-pattern-gr", eBayerPatternGr);
bayerPatternTypeProp.map("bayer-pattern-rg", eBayerPatternRg);
BayerPatternType bayerPatternType = bayerPatternTypeProp.getValue();

Using the mapper with fluent interface

BayerPatternType bayerPatternType = Property<BayerPatternType>("VisionX.Capturer.BayerPatternType", properties, eBayerPatternRg)
.map("bayer-pattern-bg", eBayerPatternBg)
.map("bayer-pattern-gb", eBayerPatternGb)
.map("bayer-pattern-gr", eBayerPatternGr)
.map("bayer-pattern-rg", eBayerPatternRg)
.setCaseInsensitive(true)
.getValue();

The method chaining can be terminated at any time. Thus, using the fluent interface is optional as shown by the previous examples.

Generic property type mapping

The Ice::Properties support only string and integer return values without any validation, whereas the armarx::Property is able to return any type you specify for the typename PropertyType. The mapping of strings onto PropertyType values is done by means of map(string valueString, PropertyType value). The following examples maps string words onto boolean values:

bool usingFormat7Mode = Property<bool>("VisionX.Capturer.Format7Mode", properties, false)
.map("true", true)
.map("yes", true)
.map("1", true)
.map("false", false)
.map("no", false)
.map("0", false)
.getValue();

Sometimes you only need to convert a string into a numeric value or even want to get the raw string itself. The return value type depends on which value retrieval function you use. These come in three types:

  1. typename PropertyType requires mapping and is accessible by the following functions:
    PropertyType getValue()
    • It's specified in the template parameter: Property<PropertyType> (e.g. Property<float>(...))
    • Returns one of the mapped values of the type PropertyType you specified
    • Throws a MissingRequiredPropertyException if the property is not defined and set as required
    • Throws a UnmappedValueException if value is not mapped.
    • Throws a InvalidPropertyValueException if the syntax of the value is incorrect.
PropertyType getValueOrDefault()

typename NumericType requires no mapping, performs a lexical cast and is accessible by the following functions:

NumericType getNumericValue<NumericType>()
NumericType getNumericValueOrDefault<NumericType>()

std::string raw string property value. Requires no mapping and is accessible by the following functions:

std::string getRawStringValue();
std::string getRawStringValue(std::string default);

As you may have noticed, for each of the three value types there are two functions. One that throws error specific exceptions and one that never throws. Instead it returns a default value on errors. It is up to the developer which one of the functions shall be used.

Property requirement check

In few cases a component may require configuration values in order to proceed, assuming no default value is known at compile time. To assert that a certain property value has been defined you may tell the mapper that the property is required. If the property is not set, an exception is thrown while trying to get the value from the mapper (e.g. by calling getValue()):

try
{
std::string uidStr = Property<std::string>("VisionX.Capturer.CameraUIDs", properties, "")
.setRequired(true)
.getRawStringValue();
}
{
std::cout << "Cannot run without Camera UIDs. Terminating ..." << std::endl;
exit(1);
}

Property value mapping validation

The getValue() function will throw an armarx::exceptions::local::UnmappedValueException if the property value is not mapped. The following examples shows this case:

// config file
...
VisionX.Capturer.Format7Mode = yes
...
// component
...
bool usingFormat7Mode = Property<bool>("VisionX.Capturer.Format7Mode", properties, false)
.map("1", true)
.map("0", false)
.getValue();
...

Since the word "yes" is not mapped, an exception is thrown. If you want to avoid the exception you may use the getValueOrDefault() function which will return the default value specified in the constructor instead of throwing an exception.

Property value validation by regular expression matching

It's in many cases easier to parse and interpret values if they match a certain pattern. For example assume we need two camera UIDs to initialize the stereo capturer. Each UID must have a length of 16 characters and consist solely of numbers and the letters A-F and finally the UIDs should be separated only by a comma or whitespace. At this point regular expressions come in handy to assert this pattern:

// Camera UIDs
std::string uidStr = Property<std::string>(propPrefix + ".CameraUIDs", properties, "")
.setRequired(true)
.setMatchRegex("\\s*[a-zA-Z0-9]{16}\\s*((,|\\s)\\s*[a-zA-Z0-9]{16})")
.getRawStringValue();

Numeric property values and the min. & max. value limitation

The Property supports simple lexical cast for numeric values. If the cast failes due to wrong numeric syntax, an armarx::exceptions::local::InvalidPropertyValueException is thrown. Numeric value boundaries may be defined by the functions setMin() and setMax(). The bounds are asstered when using the getNumericValue(). If the property value is out of bounds, the armarx::exceptions::local::ValueRangeExceededException will be thrown. Again, the exceptions can be avoided by using the getNumericValueOrDefault() instead.

Support of case sensitive and case insensitive value mapping

bool usingFormat7Mode = Property<bool>("VisionX.Capturer.Format7Mode", properties, false)
.setCaseInsensitive(true)
.map("yes", true)
.map("no", false)
.getValue();

The mapper in the example above would map the words "Yes" and "YES" onto true as well, since it acts case-insensitive. This avoids many tedious mapping and permitting less restrictive inputs. The setCaseInsensitive(bool) function can be called at any time during the mapping.

armarx::control::common::getValue
T getValue(nlohmann::json &userConfig, nlohmann::json &defaultConfig, const std::string &entryName)
Definition: utils.h:55
armarx::viz::toString
const char * toString(InteractionFeedbackType type)
Definition: Interaction.h:27
armarx::exceptions::local::MissingRequiredPropertyException
This exception is thrown if a property marked as required has not been specified.
Definition: MissingRequiredPropertyException.h:48
armarx::PropertyDefinitionsPtr
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
Definition: forward_declarations.h:34