1 // Copyright (C) 2018-2019 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #ifndef STAMPED_VALUE_H
8 #define STAMPED_VALUE_H
9 
10 #include <cc/data.h>
11 #include <cc/stamped_element.h>
12 #include <boost/multi_index/hashed_index.hpp>
13 #include <boost/multi_index/mem_fun.hpp>
14 #include <boost/multi_index/ordered_index.hpp>
15 #include <boost/multi_index_container.hpp>
16 #include <boost/shared_ptr.hpp>
17 #include <cstdint>
18 #include <string>
19 
20 namespace isc {
21 namespace data {
22 
23 class StampedValue;
24 
25 /// @brief Pointer to the stamped value.
26 typedef boost::shared_ptr<StampedValue> StampedValuePtr;
27 
28 /// @brief This class represents a named configuration parameter,
29 /// e.g. global parameter of the DHCP server.
30 ///
31 /// Global configuration elements having simple types, e.g. DHCP
32 /// timers, need to be associatied with modification timestamps.
33 /// This association is made by deriving from @c StampedElement.
34 /// The values can be strings, integers, booleans or real numbers.
35 ///
36 /// Because the strings are more flexible, configuration elements
37 /// are always held as strings in the configuration backends. This
38 /// class reflects a single value held in the database. The value
39 /// can be return in its orginal type or can be returned as a
40 /// string. Also the null values are allowed.
41 class StampedValue : public StampedElement {
42 public:
43 
44     /// @brief Constructor creating a null value.
45     ///
46     /// @param name Name of the value.
47     StampedValue(const std::string& name);
48 
49     /// @brief Constructor creating a value from the @c Element.
50     ///
51     /// @param name Name of the value.
52     /// @param value Value encapsulated in the @c Element object.
53     ///
54     /// @throw BadValue if the value is null.
55     /// @throw TypeError if the value is neither a string, integer,
56     /// bool nor real.
57     StampedValue(const std::string& name, const ElementPtr& value);
58 
59     /// @brief Constructor creating a string value.
60     ///
61     /// Creates stamped value from a string.
62     ///
63     /// @param name Name of the value.
64     /// @param value Value to be set.
65     StampedValue(const std::string& name, const std::string& value);
66 
67     /// @brief Factory function creating a null value.
68     ///
69     /// @param name Name of the value.
70     static StampedValuePtr create(const std::string& name);
71 
72     /// @brief Factory function creating a value from the @c Element.
73     ///
74     /// @param name Name of the value.
75     /// @param value Value encapsulated in the @c Element object.
76     ///
77     /// @throw BadValue if the value is null.
78     /// @throw TypeError if the value is neither a string, integer,
79     /// bool nor real.
80     static StampedValuePtr create(const std::string& name,
81                                   const ElementPtr& value);
82 
83     /// @brief Factory function creating a string value.
84     ///
85     /// Creates stamped value from a string.
86     ///
87     /// @param name Name of the value.
88     /// @param value Value to be set.
89     static StampedValuePtr create(const std::string& name,
90                                   const std::string& value);
91 
92     /// @brief Factory function which attempts to convert provided
93     /// string value to a given type.
94     ///
95     /// This factory function is useful in cases when the value is
96     /// read as a string from a database. The string value has to
97     /// be converted to the appropriate data type. The type is also
98     /// known from the database.
99     ///
100     /// @param name Name of the value.
101     /// @param value Value given as string to be converted.
102     /// @param type Type of the value to convert to.
103     static StampedValuePtr create(const std::string& name,
104                                   const std::string& value,
105                                   Element::types type);
106 
107     /// @brief Returns a type of the value.
108     ///
109     /// @return Type of the value as integer. It can be compared
110     /// with the @c Element::getType() output.
111     /// @throw InvalidOperation if the value is null.
112     int getType() const;
113 
114     /// @brief Returns value name.
115     ///
116     /// @return Value name.
getName()117     std::string getName() const {
118         return (name_);
119     }
120 
121     /// @brief Returns value as string.
122     ///
123     /// It is allowed to call this function for all supported data
124     /// types. They are converted to a string. For example, a real
125     /// number of 1.4 will be returned as "1.4". The boolean true
126     /// value will be returned as "1" etc.
127     ///
128     /// @return Stored value as string.
129     /// @throw InvalidOperation if the value is null.
130     std::string getValue() const;
131 
132     /// @brief Checks if the value is null.
133     ///
134     /// @return true if the value is null, false otherwise.
amNull()135     bool amNull() const {
136         return (!value_);
137     }
138 
139     /// @brief Returns value as signed integer.
140     ///
141     /// @return Stored value as a signed integer.
142     /// @throw TypeError if the value is not of @c Element::integer
143     /// type.
144     int64_t getIntegerValue() const;
145 
146     /// @brief Returns value as a boolean.
147     ///
148     /// @return Stored value as a boolean.
149     /// @throw TypeError if the value is not of @c Element::boolean
150     /// type.
151     bool getBoolValue() const;
152 
153     /// @brief Returns value as a real number.
154     ///
155     /// @return Stored value as a real number.
156     /// @throw TypeError if the value is not of @c Element::real
157     /// type.
158     double getDoubleValue() const;
159 
160     /// @brief Returns the value as @c Element.
getElementValue()161     ConstElementPtr getElementValue() const {
162         return (value_);
163     }
164 
165 private:
166 
167     /// @brief Checks if the values passed to the constructors
168     /// were correct.
169     ///
170     /// This is called from the constructors.
171     ///
172     /// @throw BadValue if the value is null.
173     /// @throw TypeError if the value type is neither a string,
174     /// integer, boolean nor real.
175     void validateConstruct() const;
176 
177     /// @brief Checks if the value is accessed correctly.
178     ///
179     /// This is called from the accessors of this class.
180     ///
181     /// @param type Type of the value expected by the accessor
182     /// function.
183     ///
184     /// @throw InvalidOperation if the accessed value is null.
185     /// @throw TypeError if the expected type is not a string
186     /// and it doesn't match the value type.
187     void validateAccess(Element::types type) const;
188 
189     /// @brief Name of the value.
190     std::string name_;
191 
192     /// @brief Stored value.
193     ElementPtr value_;
194 };
195 
196 /// @name Definition of the multi index container for @c StampedValue.
197 ///
198 //@{
199 
200 /// @brief Tag for the index for access by value name.
201 struct StampedValueNameIndexTag { };
202 
203 /// @brief Tag for the index for access by modification time.
204 struct StampedValueModificationTimeIndexTag { };
205 
206 /// @brief Multi index container for @c StampedValue.
207 typedef boost::multi_index_container<
208     StampedValuePtr,
209     boost::multi_index::indexed_by<
210         // Index used to access value by name.
211         boost::multi_index::hashed_non_unique<
212             boost::multi_index::tag<StampedValueNameIndexTag>,
213             boost::multi_index::const_mem_fun<
214                 StampedValue,
215                 std::string,
216                 &StampedValue::getName
217             >
218         >,
219 
220         // Index used to access value by modification time.
221         boost::multi_index::ordered_non_unique<
222             boost::multi_index::tag<StampedValueModificationTimeIndexTag>,
223             boost::multi_index::const_mem_fun<
224                 BaseStampedElement,
225                 boost::posix_time::ptime,
226                 &BaseStampedElement::getModificationTime
227             >
228         >
229     >
230 > StampedValueCollection;
231 
232 //@}
233 
234 } // end of namespace isc::data
235 } // end of namespace isc
236 
237 #endif
238