Provide a protocol for containers holding logging attributes.
More...
Namespaces |
namespace | ball |
Detailed Description
- Outline
-
-
- Purpose:
- Provide a protocol for containers holding logging attributes.
-
- Classes:
-
- See also:
- Component ball_attribute, Component ball_defaultattributecontainer
-
- Description:
- This component defines a protocol class,
ball::AttributeContainer
, for containers of ball::Attribute
values. The ball::AttributeContainer
protocol primarily provides a hasValue()
method, allowing clients to determine if a given attribute value is held by the container.
- This component participates in the implementation of "Rule-Based Logging". For more information on how to use that feature, please see the package level documentation and usage examples for "Rule-Based Logging".
-
- Usage:
- In the following examples we examine two derived implementations of the
ball::AttributeContainer
protocol. The first implementation is potentially more efficient, holding a specific group of attributes relevant to a particular application. The second implementation is more general, and can hold any valid ball::Attribute
value. In the final example we demonstrate how to call the methods of the ball::AttributeContainer
protocol.
-
- Example 1: An Implementation of ball::AttributeContainer:
- In the following example we develop a
ball::AttributeContainer
implementation specifically intended for a service offline that will perform rule-based logging, governed by the service client's Bloomberg "uuid", "luw", and "firm number". We define a class ServiceAttributes
that contains three integer ball::Attribute
values having the names "uuid", "luw", and "firmNumber".
- Note that this implementation requires no memory allocation, so it will be more efficient than a more general set-based implementation if the container is frequently created, destroyed, or modified. We will develop a
ball::AttributeContainer
implementation that can hold any ball::Attribute
value in example 2 (and one is provided by the ball
package in the ball_defaultattributecontainer
component).
class ServiceAttributes : public ball::AttributeContainer {
Note that we use the type ball::Attribute
for our data members for simplicity. It would be a little more efficient to use int
data members, but the implementation of hasValue()
would be less readable.
ball::Attribute d_uuid;
ball::Attribute d_luw;
ball::Attribute d_firmNumber;
public:
static const char * const UUID_ATTRIBUTE_NAME;
static const char * const LUW_ATTRIBUTE_NAME;
static const char * const FIRMNUMBER_ATTRIBUTE_NAME;
ServiceAttributes(int uuid, int luw, int firmNumber);
virtual ~ServiceAttributes();
virtual bool hasValue(const ball::Attribute& value) const;
virtual bsl::ostream& print(bsl::ostream& stream,
int level = 0,
int spacesPerLevel = 4) const;
virtual void visitAttributes(
const bsl::function<void(const ball::Attribute&)>& visitor) const;
};
inline
ServiceAttributes::ServiceAttributes(int uuid, int luw, int firmNumber)
: d_uuid(UUID_ATTRIBUTE_NAME, uuid)
, d_luw(LUW_ATTRIBUTE_NAME, luw)
, d_firmNumber(FIRMNUMBER_ATTRIBUTE_NAME, firmNumber)
{
}
const char * const ServiceAttributes::UUID_ATTRIBUTE_NAME = "uuid";
const char * const ServiceAttributes::LUW_ATTRIBUTE_NAME = "luw";
const char * const ServiceAttributes::FIRMNUMBER_ATTRIBUTE_NAME =
"firmNumber";
ServiceAttributes::~ServiceAttributes()
{
}
bool ServiceAttributes::hasValue(const ball::Attribute& value) const
{
return d_uuid == value || d_luw == value || d_firmNumber == value;
}
bsl::ostream& ServiceAttributes::print(bsl::ostream& stream,
int level,
int spacesPerLevel) const
{
bslim::Printer printer(&stream, level, spacesPerLevel);
printer.start();
printer.printAttribute("uuid", d_uuid);
printer.printAttribute("luw", d_luw);
printer.printAttribute("firmNumber", d_firmNumber);
printer.end();
return stream;
}
void ServiceAttributes::visitAttributes(
const bsl::function<void(const ball::Attribute&)> &visitor) const
{
visitor(d_uuid);
visitor(d_luw);
visitor(d_firmNumber);
}
-
- Example 2: A Generic Implementation of ball::AttributeContainer:
- In this second example we define a
ball::AttributeContainer
that can contain any valid ball::Attribute
value (a "generic" ball::AttributeContainer
). In practice, an implementation that can contain any attribute values may be less efficient than one specifically created for a particular group of attributes needed by an application (as shown in Example 1).
- Note that the
ball
package provides a similar ball::AttributeContainer
implementation in the ball_defaultattributecontainer
component.
class AttributeSet : public ball::AttributeContainer {
To define an STL set (or hash set) for ball::Attribute
values, we must define a comparison (or hash) operation for attribute values. Here we define a comparison functor that compares attributes by name, then by value-type, and finally by value. struct AttributeComparator {
bool operator()(const ball::Attribute& lhs,
const ball::Attribute& rhs) const
{
int cmp = bsl::strcmp(lhs.name(), rhs.name());
if (0 != cmp) {
return cmp < 0;
}
if (lhs.value().typeIndex() != rhs.value().typeIndex()) {
return lhs.value().typeIndex() < rhs.value().typeIndex();
}
switch (lhs.value().typeIndex()) {
case 0:
return true;
case 1:
return lhs.value().the<int>() < rhs.value().the<int>();
case 2:
return lhs.value().the<long>() < rhs.value().the<long>();
case 3:
return lhs.value().the<long long>()
< rhs.value().the<long long>();
case 4:
return lhs.value().the<unsigned int>()
< rhs.value().the<unsigned int>();
case 5:
return lhs.value().the<unsigned long>()
< rhs.value().the<unsigned long>();
case 6:
return lhs.value().the<unsigned long long>()
< rhs.value().the<unsigned long long>();
case 7:
return lhs.value().the<bsl::string>() <
rhs.value().the<bsl::string>();
case 8:
return lhs.value().the<const void *>() <
rhs.value().the<const void *>();
}
BSLS_ASSERT(false);
return false;
}
};
bsl::set<ball::Attribute, AttributeComparator> d_set;
public:
AttributeSet(bslma::Allocator *basicAllocator = 0);
virtual ~AttributeSet();
void insert(const ball::Attribute& value);
bool remove(const ball::Attribute& value);
virtual bool hasValue(const ball::Attribute& value) const;
virtual bsl::ostream& print(bsl::ostream& stream,
int level = 0,
int spacesPerLevel = 4) const;
virtual void visitAttributes(
const bsl::function<void(const ball::Attribute&)>& visitor) const;
};
The AttributeSet
methods are simple wrappers around bsl::set
methods:
-
- Example 3. Using a ball::AttributeContainer:
- In this final example, we demonstrate how to call the methods of the
ball::AttributeContainer
protocol.
- First we create an object of a concrete type that implements the
ball::AttributeContainer
protocol (e.g., ServiceAttributes
defined in Example 1). Then we obtain a reference to this object. We use hasValue()
to examine the values in the container: Finally we can print the attribute values in the container: bsl::cout << attributes << bsl::endl;
The resulting output should look like: [ [ uuid = 3938908 ] [ luw = 1 ] [ firmNumber = 9001 ] ]