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  *&lt;clientProperty name='transactionId' type='int'>120001&lt;/clientProperty>
 28  *&lt;clientProperty name='myKey'>Hello World&lt;/clientProperty>
 29  *&lt;clientProperty name='myBlob' type='byte[]' encoding='base64'>OKFKAL==&lt;/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