BDE 4.14.0 Production release
Loading...
Searching...
No Matches
ball_attributecontainer

Detailed Description

Outline

Purpose

Provide a protocol for containers holding logging attributes.

Classes

See also
ball_attribute, 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).

// serviceattributes.h
/// Provide a concrete implementation of the `ball::AttributeContainer`
/// that holds the `uuid`, `luw`, and `firmNumber` associated with a
/// request to the example service. This concrete container
/// exposes those properties in attributes named "uuid", "luw", and
/// "firmNumber" respectively.
class ServiceAttributes : public ball::AttributeContainer {
Definition ball_attributecontainer.h:426

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.

// DATA
ball::Attribute d_uuid; // Bloomberg user id
ball::Attribute d_luw; // Bloomberg luw
ball::Attribute d_firmNumber; // Bloomberg firm number
// ...
public:
// PUBLIC CONSTANTS
// The names of the attributes exposed by this attribute container.
static const char * const UUID_ATTRIBUTE_NAME;
static const char * const LUW_ATTRIBUTE_NAME;
static const char * const FIRMNUMBER_ATTRIBUTE_NAME;
// CREATORS
/// Create a service-attributes object with the specified `uuid`,
/// `luw`, and `firmNumber`.
ServiceAttributes(int uuid, int luw, int firmNumber);
virtual ~ServiceAttributes();
// Destroy this service-attributes object.
// ACCESSORS
/// Return `true` if the attribute having specified `value` exists
/// in this object, and `false` otherwise. This implementation will
/// return `true` if `value.name()` equals "uuid", "luw", or "firm"
/// and `value.value()` is an `int` equal to the corresponding
/// property value supplied at construction.
virtual bool hasValue(const ball::Attribute& value) const;
/// Format this object to the specified output `stream`.
virtual bsl::ostream& print(bsl::ostream& stream,
int level = 0,
int spacesPerLevel = 4) const;
/// Invoke the specified `visitor` function for all attributes in
/// this container.
virtual void visitAttributes(
const bsl::function<void(const ball::Attribute&)>& visitor) const;
};
// CREATORS
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)
{
}
// serviceattributes.cpp
// PUBLIC CONSTANTS
const char * const ServiceAttributes::UUID_ATTRIBUTE_NAME = "uuid";
const char * const ServiceAttributes::LUW_ATTRIBUTE_NAME = "luw";
const char * const ServiceAttributes::FIRMNUMBER_ATTRIBUTE_NAME =
"firmNumber";
// CREATORS
ServiceAttributes::~ServiceAttributes()
{
}
// ACCESSORS
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);
}
Definition ball_attribute.h:198
Forward declaration.
Definition bslstl_function.h:934
Definition bslim_printer.h:601

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.

// attributeset.h
/// A simple set-based implementation of the `ball::AttributeContainer`
/// protocol, used for testing.
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 {
/// Return `true` if the specified `lhs` attribute is ordered
/// before the specified `rhs` attribute, and `false` otherwise.
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: // unset
return true;
case 1: // int
return lhs.value().the<int>() < rhs.value().the<int>();
case 2: // long
return lhs.value().the<long>() < rhs.value().the<long>();
case 3: // long long
return lhs.value().the<long long>()
< rhs.value().the<long long>();
case 4: // unsigned int
return lhs.value().the<unsigned int>()
< rhs.value().the<unsigned int>();
case 5: // unsigned long
return lhs.value().the<unsigned long>()
< rhs.value().the<unsigned long>();
case 6: // unsigned long long
return lhs.value().the<unsigned long long>()
< rhs.value().the<unsigned long long>();
case 7: // string
return lhs.value().the<bsl::string>() <
rhs.value().the<bsl::string>();
case 8: // const void *
return lhs.value().the<const void *>() <
rhs.value().the<const void *>();
case 9: // Guid
return lhs.value().the<bdlb::Guid>() <
rhs.value().the<bdlb::Guid>();
}
BSLS_ASSERT(false);
return false;
}
};
// DATA
public:
// CREATORS
/// Create an attribute set.
AttributeSet(bslma::Allocator *basicAllocator = 0);
/// Destroy this attribute set.
virtual ~AttributeSet();
// MANIPULATORS
/// Add the specified value to this attribute set.
void insert(const ball::Attribute& value);
/// Remove the specified value from this attribute set. Return
/// `true` if the attribute was found, and `false` if `value` was
/// not a member of this set.
bool remove(const ball::Attribute& value);
// ACCESSORS
/// Return `true` if the attribute having specified `value` exists
/// in this object, and `false` otherwise.
virtual bool hasValue(const ball::Attribute& value) const;
/// Format this object to the specified output `stream` at the
/// (absolute value of) the optionally specified indentation `level`
/// and return a reference to `stream`.
virtual bsl::ostream& print(bsl::ostream& stream,
int level = 0,
int spacesPerLevel = 4) const;
/// Invoke the specified `visitor` function for all attributes in
/// this container.
virtual void visitAttributes(
const bsl::function<void(const ball::Attribute&)>& visitor) const;
};
const char * name() const
Return the name of this object.
Definition ball_attribute.h:643
const Value & value() const
Definition ball_attribute.h:649
Definition bdlb_guid.h:201
int typeIndex() const
Definition bdlb_variant.h:7646
TYPE & the()
Definition bdlb_variant.h:7517
Definition bslstl_string.h:1281
Definition bslstl_set.h:657
Definition bslma_allocator.h:457
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
bsl::ostream & print(bsl::ostream &stream, const TYPE &object, int level=0, int spacesPerLevel=4)
Definition bdlb_printmethods.h:719

The AttributeSet methods are simple wrappers around bsl::set methods:

inline
AttributeSet::AttributeSet(bslma::Allocator *basicAllocator)
: d_set(AttributeComparator(), basicAllocator)
{
}
// MANIPULATORS
inline
void AttributeSet::insert(const ball::Attribute& value)
{
d_set.insert(value);
}
inline
bool AttributeSet::remove(const ball::Attribute& value)
{
return d_set.erase(value) > 0;
}
// attributeset.cpp
// CREATORS
AttributeSet::~AttributeSet()
{
}
// ACCESSORS
bool AttributeSet::hasValue(const ball::Attribute& value) const
{
return d_set.find(value) != d_set.end();
}
bsl::ostream& AttributeSet::print(bsl::ostream& stream,
int level,
int spacesPerLevel) const
{
bslim::Printer printer(&stream, level, spacesPerLevel);
printer.start();
= d_set.begin();
for (; it != d_set.end(); ++it) {
printer.printValue(*it);
}
printer.end();
return stream;
}
void AttributeSet::visitAttributes(
const bsl::function<void(const ball::Attribute&)> &visitor) const
{
= d_set.begin();
for (; it != d_set.end(); ++it) {
visitor(*it);
}
}
pair< iterator, bool > insert(const value_type &value)
Definition bslstl_set.h:2326
set &operator=(BloombergLP::bslmf::MovableRef< set > rhs) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(AllocatorTraits iterator begin() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_set.h:2294
iterator find(const key_type &key)
Definition bslstl_set.h:1191
BloombergLP::bslstl::TreeIterator< const value_type, Node, difference_type > const_iterator
Definition bslstl_set.h:762
iterator end() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_set.h:2302
iterator erase(const_iterator position)
Definition bslstl_set.h:2544

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.

ServiceAttributes serviceAttributes(3938908, 1, 9001);
const ball::AttributeContainer& attributes = serviceAttributes;

We use hasValue() to examine the values in the container:

assert(true == attributes.hasValue(ball::Attribute("uuid", 3938908)));
assert(true == attributes.hasValue(ball::Attribute("luw", 1)));
assert(true == attributes.hasValue(ball::Attribute("firmNumber", 9001)));
assert(false == attributes.hasValue(ball::Attribute("uuid", 1391015)));
assert(false == attributes.hasValue(ball::Attribute("luw", 2)));
assert(false == attributes.hasValue(ball::Attribute("bad name", 3938908)));
virtual bool hasValue(const Attribute &value) const =0

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 ] ]