// ball_attributecontainer.h -*-C++-*- #ifndef INCLUDED_BALL_ATTRIBUTECONTAINER #define INCLUDED_BALL_ATTRIBUTECONTAINER #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a protocol for containers holding logging attributes. // //@CLASSES: // ball::AttributeContainer: a protocol for a collection of attributes // //@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 // // class ServiceAttributes : public ball::AttributeContainer { // // 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. // //.. // 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 // static const char * const UUID_ATTRIBUTE_NAME; // static const char * const LUW_ATTRIBUTE_NAME; // static const char * const FIRMNUMBER_ATTRIBUTE_NAME; // // The names of the attributes exposed by this attribute container. // // // CREATORS // ServiceAttributes(int uuid, int luw, int firmNumber); // // Create a service-attributes object with the specified 'uuid', // // 'luw', and 'firmNumber'. // // virtual ~ServiceAttributes(); // // Destroy this service-attributes object. // // // ACCESSORS // virtual bool hasValue(const ball::Attribute& value) const; // // 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 bsl::ostream& print(bsl::ostream& stream, // int level = 0, // int spacesPerLevel = 4) const; // // Format this object to the specified output 'stream'. // // virtual void visitAttributes( // const bsl::function<void(const ball::Attribute&)>& visitor) const; // // Invoke the specified 'visitor' function for all attributes in // // this container. // }; // // // 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); // } //.. // ///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 // // class AttributeSet : public ball::AttributeContainer { // // A simple set-based implementation of the 'ball::AttributeContainer' // // protocol, used for testing. // //.. // 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 // // Return 'true' if the specified 'lhs' attribute is ordered // // before the specified 'rhs' attribute, and 'false' otherwise. // { // 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 *>(); // } // BSLS_ASSERT(false); // return false; // } // }; // // // DATA // bsl::set<ball::Attribute, AttributeComparator> d_set; // // public: // // CREATORS // AttributeSet(bslma::Allocator *basicAllocator = 0); // // Create an attribute set. // // virtual ~AttributeSet(); // // Destroy this attribute set. // // // MANIPULATORS // void insert(const ball::Attribute& value); // // Add the specified value to this attribute set. // // bool remove(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. // // // ACCESSORS // virtual bool hasValue(const ball::Attribute& value) const; // // Return 'true' if the attribute having specified 'value' exists // // in this object, and 'false' otherwise. // // virtual bsl::ostream& print(bsl::ostream& stream, // int level = 0, // int spacesPerLevel = 4) 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 void visitAttributes( // const bsl::function<void(const ball::Attribute&)>& visitor) const; // // Invoke the specified 'visitor' function for all attributes in // // this container. // }; //.. // 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(); // // bsl::set<ball::Attribute, AttributeComparator>::const_iterator it // = 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 // { // bsl::set<ball::Attribute, AttributeComparator>::const_iterator it // = d_set.begin(); // for (; it != d_set.end(); ++it) { // visitor(*it); // } // } //.. // ///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))); //.. // 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 ] ] //.. #include <balscm_version.h> #include <bsl_functional.h> #include <bsl_iosfwd.h> namespace BloombergLP { namespace ball { class Attribute; // ======================== // class AttributeContainer // ======================== class AttributeContainer { // This class defines a protocol for a container of attribute values. The // attribute container provides a 'hasValue()' method to determine whether // an attribute value is in the container. public: // CREATORS virtual ~AttributeContainer(); // Destroy this object. // ACCESSORS virtual bool hasValue(const Attribute& value) const = 0; // Return 'true' if a attribute having the specified 'value' exists in // this object, and 'false' otherwise. virtual bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const = 0; // Format this object to the specified output 'stream' at the (absolute // value of) the optionally specified indentation 'level' and return a // reference to 'stream'. If 'level' is specified, optionally specify // 'spacesPerLevel', the number of spaces per indentation level for // this and all of its nested objects. If 'level' is negative, // suppress indentation of the first line. If 'spacesPerLevel' is // negative, format the entire output on one line, suppressing all but // the initial indentation (as governed by 'level'). If 'stream' is // not valid on entry, this operation has no effect. virtual void visitAttributes( const bsl::function<void(const ball::Attribute&)>& visitor) const = 0; // Invoke the specified 'visitor' function for all attributes in this // container. }; // FREE OPERATORS bsl::ostream& operator<<(bsl::ostream& stream, const AttributeContainer& container); // Write the value of the specified 'container' to the specified output // 'stream' in a single-line format, and return a reference to the // modifiable stream. // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ------------------------ // class AttributeContainer // ------------------------ } // close package namespace // FREE OPERATORS inline bsl::ostream& ball::operator<<(bsl::ostream& stream, const AttributeContainer& container) { return container.print(stream, 0, -1); } } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2015 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------