1 /*------------------------------------------------------------------------------
2 Name: ClientProperty.h
3 Project: xmlBlaster.org
4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
5 Comment: Handling one client property of QosData
6 ------------------------------------------------------------------------------*/
7 #ifndef _UTIL_QOS_CLIENTPROPERTY_H
8 #define _UTIL_QOS_CLIENTPROPERTY_H
9
10 #include <util/xmlBlasterDef.h>
11 #include <util/Constants.h>
12 #include <util/Base64.h>
13 #include <util/lexical_cast.h>
14 #include <typeinfo>
15 #include <vector>
16 #include <string>
17 #include <iostream> // temporary for cerr
18 #include <iterator>
19
20 namespace org { namespace xmlBlaster { namespace util { namespace qos {
21
22 /**
23 * This class encapsulates one client property in a QoS.
24 * <p/>
25 * Examples:
26 * <pre>
27 *<clientProperty name='transactionId' type='int'>120001</clientProperty>
28 *<clientProperty name='myKey'>Hello World</clientProperty>
29 *<clientProperty name='myBlob' type='byte[]' encoding='base64'>OKFKAL==</clientProperty>
30 * </pre>
31 * If the attribute <code>type</code> is missing we assume a 'String' property
32 *
33 * <h3>Charactersets other than US-ASCII (7bit)</h3>
34 * <p>For international character sets like "UTF-8" or "iso-8859-1"
35 * you need to force the <tt>type</tt> to <tt>Constants::TYPE_BLOB</tt> which
36 * will send the data base64 encoded.</p>
37 * <p>The key name may only consist of US-ASCII characters</p>
38 *
39 * @author <a href="mailto:xmlBlaster@marcelruff.info">Marcel Ruff</a>
40 * @see <a href="http://www.xmlblaster.org/xmlBlaster/doc/requirements/engine.qos.clientProperty.html">The client.qos.clientProperty requirement</a>
41 * @see TestClientProperty
42 */
43 class Dll_Export ClientProperty
44 {
45 private:
46 /** The unique key */
47 std::string name_; // Can't be const because of: operator=() error: non-static const member `const std::string name_', can't use default assignment operator
48 /** The value encoded as specified with encoding_ */
49 std::string value_;
50 std::string encoding_;
51 mutable std::string type_;
52 mutable std::string charset_;
53
54 template <typename T_VALUE> void guessType(const T_VALUE& value) const;
55 bool needsEncoding() const;
56
57 public:
58
59 /**
60 * Standard constructor.
61 * A typical example is:
62 * <pre>
63 * ClientProperty("myKey", "myValue");
64 * </pre>
65 * If you want to send a string in your own locale character set:
66 * <pre>
67 * ClientProperty("myKey", "myValue", Constants::TYPE_STRING, Constants::ENCODING_BASE64, "windows-1252");
68 * </pre>
69 * @param name The unique property key in US-ASCII encoding (7-bit), UTF-8 should work as well
70 * A duplicate key will overwrite the old setting
71 * @param value Your data . The type (like "float") is guessed from T_VALUE
72 * NOTE: "vector<unsigned char>" "unsigned char*" are
73 * treated as BLOBs and will be transferred Base64 encoded.
74 * @param type The data type of the value, optional, e.g. Constants::TYPE_FLOAT ("float")
75 * @param encoding How the data is transferred, org::xmlBlaster::util::Constants::ENCODING_BASE64 or ""
76 * @param charset XmlBlaster expects all XML strings as UTF-8, however you can send your client properties
77 * in any other charset but you must then encode it with ENCODING_BASE64 and pass the charset used, for example "windows-1252".
78 * Please use the official IANA charset names.
79 * @see http://www.iana.org/assignments/charset-reg/
80 */
81 template <typename T_VALUE> ClientProperty(
82 const std::string& name,
83 const T_VALUE& value,
84 const std::string& type="",
85 const std::string& encoding="",
86 const std::string& charset=""
87 );
88
89 /**
90 * Constructor called by SAX parser.
91 * Nothing is interpreted, all values are set as given
92 * @param dummy To distinguish the constructor from the others
93 */
94 ClientProperty(bool dummy,
95 const std::string& name,
96 const std::string& type,
97 const std::string& encoding,
98 const std::string& charset
99 );
100
101 /**
102 * Specialized ctor for literal data.
103 * @param name The unique property key in US-ASCII encoding (7-bit)
104 * @param value Your pointer to data
105 * @param type Optionally you can force another type than "String",
106 * for example Constant::TYPE_DOUBLE if the pointer contains
107 * such a number as a string representation.
108 */
109 ClientProperty(const std::string& name,
110 const char *value,
111 const std::string& type="");
112
113 /**
114 * Specialized ctor for blob data.
115 * @param name The unique property key in US-ASCII encoding (7-bit)
116 * @param value Your BLOB data.
117 * @param type Optionally you can force another type than "byte[]",
118 * for example Constant::TYPE_DOUBLE if the vector contains
119 * such a number as a string representation.
120 */
121 ClientProperty(const std::string& name,
122 const std::vector<unsigned char>& value,
123 const std::string& type="");
124
125 /**
126 * Internal constructor only, used by SAX parser in conjunction with setValueRaw()
127 * @param name The unique property key in US-ASCII encoding (7-bit)
128 * @param value Your data.
129 * @param type for example Constant::TYPE_STRING
130 * @param encoding Constants::ENCODING_BASE64 or "" for plain text
131 ClientProperty(const std::string& name,
132 const std::string& value,
133 const std::string& type,
134 const std::string& encoding);
135 */
136
137 //virtual ~ClientProperty();
138
139 /**
140 * The unique key of the property.
141 * @return The key string
142 */
143 const std::string& getName() const;
144
145 /**
146 * Get the data type of the property value.
147 * @return The data type, for example "short" or "byte[]" for "vector<unsigned char>"
148 * @see Constants::TYPE_SHORT
149 * @see Constants::TYPE_BLOB
150 */
151 std::string getType() const;
152
153 /**
154 * Get the internally used encoding to transfer data to/from xmlBlaster.
155 * @return The used encoding, for example "base64" or "" for none
156 * @see Constants::ENCODING_BASE64
157 */
158 std::string getEncoding() const;
159
160 /**
161 * If value is of type "String" and base64 encoded you can specify a charset (like "UTF-8" or "windows-1252")
162 * @return The used encoding, for example "base64" or "" for none
163 * @see Constants::ENCODING_BASE64
164 */
165 std::string getCharset() const;
166
167 /**
168 * Set a charset, needed only it not "UTF-8" (default).
169 * @param charset e.g. "windows-1252"
170 */
171 void setCharset(const std::string& charset);
172
173 /**
174 * Check if getValueRaw() is Base64 encoded
175 */
176 bool isBase64() const;
177
178 /**
179 * The raw, possibly still Base64 encoded value
180 */
181 std::string getValueRaw() const;
182
183 /**
184 * Convenience method for getValue(T_VALUE&).
185 * @return The value. It is decoded (readable) in case it was base64 encoded
186 */
187 std::string getStringValue() const;
188
189 /**
190 * Accessor for binary data (BLOB).
191 * @return The value. It is decoded (readable) in case it was base64 encoded
192 */
193 std::vector<unsigned char> getValue() const;
194
195 /**
196 * Access with for supported data type.
197 * @param value OUT parameter: The value in the desired data type.
198 * It is decoded (readable) in case it was base64 encoded
199 */
200 template <typename T_VALUE> void getValue(T_VALUE& value) const;
201
202 /**
203 * Set the value, it will be encoded with the encoding specified in the constructor.
204 */
205 void setValue(const std::string& value);
206
207 /**
208 * Set the already correctly encoded value, used internally by SAX parser.
209 */
210 void setValueRaw(const std::string& value);
211
212 /**
213 * Dump state of this object into a XML ASCII string.
214 * <br>
215 * @param extraOffset indenting of tags for nice output
216 * @param clearText if true the base64 for properties are dumped decoded in plain text
217 * @return internal state of the ClientProperty as a XML ASCII string
218 */
219 std::string toXml(std::string extraOffset="", bool clearText=false, std::string tagName="clientProperty") const;
220 };
221
222
223 // All template based function definitions follow here
224 // to be available outside the shared library
225 template <typename T_VALUE> ClientProperty::ClientProperty(
226 const std::string& name,
227 const T_VALUE& value,
228 const std::string& type,
229 const std::string& encoding,
230 const std::string& charset
231 )
232 : name_(name),
233 value_(""),
234 encoding_(encoding),
235 type_(type),
236 charset_(charset)
237 {
238 if (type_ == "") {
239 guessType(value); // guess type from T_VALUE
240 }
241
242 // Convert the given value type to a std::string value_
243
244 value_ = lexical_cast<std::string>(value);
245
246 if (needsEncoding()) {
247 std::vector<unsigned char> vec;
248 vec.reserve(value_.size());
249 encoding_ = org::xmlBlaster::util::Constants::ENCODING_BASE64;
250 copy(value_.begin(), value_.end(), back_inserter(vec));
251 value_ = org::xmlBlaster::util::Base64::Encode(vec);
252 }
253 }
254
255 template <typename T_VALUE> void ClientProperty::guessType(const T_VALUE& value) const {
256 const char *cPC=0;
257 char *cP=0;
258 unsigned char *cUP=0;
259 const unsigned char *cUPC=0;
260 int64_t ll=0L; // Assumed to be 'long long int' (C99) == _int64 (Windows), Windows does not like double LL like 0LL;
261 std::vector<char> vc;
262 std::vector<unsigned char> vuc;
263
264 if (typeid(value) == typeid(std::string("")))
265 type_ = std::string(""); // "String"
266 else if (typeid(value) == typeid(true))
267 type_ = org::xmlBlaster::util::Constants::TYPE_BOOLEAN;
268 else if (typeid(value) == typeid(char(0)))
269 type_ = org::xmlBlaster::util::Constants::TYPE_BYTE;
270 else if (typeid(value) == typeid(cP) || typeid(value) == typeid(cPC) ||
271 typeid(value) == typeid("A") || typeid(value).name() == std::string("A13_c"))
272 type_ = std::string(""); // "String"
273 else if (typeid(value) == typeid(cUP) || typeid(value) == typeid(cUPC))
274 type_ = org::xmlBlaster::util::Constants::TYPE_BLOB;
275 else if (typeid(value) == typeid(vc) || typeid(value) == typeid(vuc))
276 type_ = org::xmlBlaster::util::Constants::TYPE_BLOB;
277 else if (typeid(value) == typeid(short(0)))
278 type_ = org::xmlBlaster::util::Constants::TYPE_SHORT;
279 else if (typeid(value) == typeid(int(0)))
280 type_ = org::xmlBlaster::util::Constants::TYPE_INT;
281 else if (typeid(value) == typeid(long(0L)))
282 type_ = org::xmlBlaster::util::Constants::TYPE_LONG;
283 else if (typeid(value) == typeid(ll))
284 type_ = org::xmlBlaster::util::Constants::TYPE_LONG;
285 else if (typeid(value) == typeid(float(1.10)))
286 type_ = org::xmlBlaster::util::Constants::TYPE_FLOAT;
287 else if (typeid(value) == typeid(double(1.7L)))
288 type_ = org::xmlBlaster::util::Constants::TYPE_DOUBLE;
289 else {
290 type_ = org::xmlBlaster::util::Constants::TYPE_BLOB;
291 std::cerr << "Warning: ClientProperty typeid=" << typeid(value).name() << " is unknown, we handle it as a blob" << std::endl;
292 }
293 }
294
295 template <typename T_VALUE> void ClientProperty::getValue(T_VALUE& value) const {
296 if (isBase64()) {
297 if (type_ == org::xmlBlaster::util::Constants::TYPE_BLOB) {
298 // TODO: detect it on compile time
299 std::cerr << "Sorry, binary data type '" << typeid(value).name()
300 << "' is not supported using getValue(value), please use 'std::vector<unsigned char> getValue()' instead"
301 << std::endl;
302 value = lexical_cast<T_VALUE>(getStringValue());
303 }
304 else {
305 value = lexical_cast<T_VALUE>(getStringValue());
306 }
307 }
308 else {
309 value = lexical_cast<T_VALUE>(value_);
310 }
311 }
312
313 }}}}
314
315 #endif
syntax highlighted by Code2HTML, v. 0.9.1