6 * Portable Windows Library
8 * Copyright (c) 2002 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
27 * Revision 1.20 2004/05/17 06:05:20 csoutheren
28 * Changed "make docs" to use doxygen
29 * Added new config file and main page
31 * Revision 1.19 2003/04/15 07:08:36 robertj
32 * Changed read and write from streams for base array classes so operates in
33 * the same way for both PIntArray and PArray<int> etc
35 * Revision 1.18 2003/04/15 03:00:41 robertj
36 * Added array support to XML/RPC
37 * Fixed XML/RPC parsing when lots of white space in raw XML, caused by
38 * big fix to base XML parser not returning internal data elements.
40 * Revision 1.17 2003/01/28 05:08:07 robertj
41 * Fixed copy constructor on function arguments and return value
43 * Revision 1.16 2002/12/16 06:57:15 robertj
44 * Added ability to specify certain elemets (by name) that are exempt from
45 * the indent formatting. Useful for XML/RPC where leading white space is
46 * not ignored by all servers.
47 * Improved the macros for defining RPC functions.
49 * Revision 1.15 2002/12/13 01:04:56 robertj
50 * Added copy constructor and assignment operator to XML/RPC structs
52 * Revision 1.14 2002/12/10 04:44:43 robertj
53 * Added support in PTime for ISO 8601 format.
55 * Revision 1.13 2002/12/09 04:06:18 robertj
56 * Added macros for defining multi-argument functions
58 * Revision 1.12 2002/12/04 02:09:26 robertj
59 * Changed macro name prefix to PXMLRPC
61 * Revision 1.11 2002/12/04 00:31:13 robertj
62 * Fixed GNU compatibility
64 * Revision 1.10 2002/12/04 00:15:56 robertj
65 * Large enhancement to create automatically encoding and decoding structures
66 * using macros to build a class.
68 * Revision 1.9 2002/11/06 22:47:24 robertj
69 * Fixed header comment (copyright etc)
71 * Revision 1.8 2002/10/02 08:54:34 craigs
72 * Added support for XMLRPC server
74 * Revision 1.7 2002/09/16 01:08:59 robertj
75 * Added #define so can select if #pragma interface/implementation is used on
76 * platform basis (eg MacOS) rather than compiler, thanks Robert Monaghan.
78 * Revision 1.6 2002/08/13 03:02:07 robertj
79 * Removed previous fix for memory leak, as object was already deleted.
81 * Revision 1.5 2002/08/13 01:55:00 craigs
82 * Fixed memory leak on PXMLRPCRequest class
84 * Revision 1.4 2002/08/06 01:04:03 robertj
85 * Fixed missing pragma interface/implementation
87 * Revision 1.3 2002/07/12 05:51:14 craigs
88 * Added structs to XMLRPC response types
90 * Revision 1.2 2002/03/27 00:50:44 craigs
91 * Fixed problems with parsing faults and creating structs
93 * Revision 1.1 2002/03/26 07:06:50 craigs
105 #include <ptclib/pxml.h>
106 #include <ptclib/url.h>
110 class PXMLRPCVariableBase
;
111 class PXMLRPCStructBase
;
114 /////////////////////////////////////////////////////////////////
116 class PXMLRPC
: public PObject
118 PCLASSINFO(PXMLRPC
, PObject
);
121 CannotCreateRequestXML
= 100,
122 CannotParseResponseXML
,
123 CannotParseRequestXML
,
125 CannotReadResponseContentBody
,
126 ResponseRootNotMethodResponse
,
128 ResponseUnknownFormat
,
130 ScalarWithoutElement
,
135 RequestHasWrongDocumentType
,
136 RequestHasNoMethodName
,
150 void SetTimeout(const PTimeInterval
& _timeout
) { timeout
= _timeout
; }
152 BOOL
MakeRequest(const PString
& method
);
153 BOOL
MakeRequest(const PString
& method
, PXMLRPCBlock
& response
);
154 BOOL
MakeRequest(PXMLRPCBlock
& request
, PXMLRPCBlock
& response
);
155 BOOL
MakeRequest(const PString
& method
, const PXMLRPCStructBase
& args
, PXMLRPCStructBase
& reply
);
157 PString
GetFaultText() const { return faultText
; }
158 PINDEX
GetFaultCode() const { return faultCode
; }
160 static BOOL
ISO8601ToPTime(const PString
& iso8601
, PTime
& val
, int tz
= PTime::GMT
);
161 static PString
PTimeToISO8601(const PTime
& val
);
164 BOOL
PerformRequest(PXMLRPCBlock
& request
, PXMLRPCBlock
& response
);
169 PTimeInterval timeout
;
173 /////////////////////////////////////////////////////////////////
175 class PXMLRPCBlock
: public PXML
177 PCLASSINFO(PXMLRPCBlock
, PXML
);
180 PXMLRPCBlock(const PString
& method
);
181 PXMLRPCBlock(const PString
& method
, const PXMLRPCStructBase
& structData
);
183 BOOL
Load(const PString
& str
);
185 PXMLElement
* GetParams();
186 PXMLElement
* GetParam(PINDEX idx
) const;
187 PINDEX
GetParamCount() const;
189 // used when used as a response
190 PINDEX
GetFaultCode() const { return faultCode
; }
191 PString
GetFaultText() const { return faultText
; }
192 void SetFault(PINDEX code
, const PString
& text
) { faultCode
= code
; faultText
= text
; }
193 BOOL
ValidateResponse();
195 // helper functions for getting parameters
196 BOOL
GetParams(PXMLRPCStructBase
& data
);
197 BOOL
GetParam(PINDEX idx
, PString
& type
, PString
& result
);
198 BOOL
GetExpectedParam(PINDEX idx
, const PString
& expectedType
, PString
& value
);
200 BOOL
GetParam(PINDEX idx
, PString
& result
);
201 BOOL
GetParam(PINDEX idx
, int & result
);
202 BOOL
GetParam(PINDEX idx
, double & result
);
203 BOOL
GetParam(PINDEX idx
, PTime
& result
, int tz
= PTime::GMT
);
204 BOOL
GetParam(PINDEX idx
, PStringToString
& result
);
205 BOOL
GetParam(PINDEX idx
, PXMLRPCStructBase
& result
);
206 BOOL
GetParam(PINDEX idx
, PStringArray
& result
);
207 BOOL
GetParam(PINDEX idx
, PArray
<PStringToString
> & result
);
209 // static functions for parsing values
210 BOOL
ParseScalar(PXMLElement
* element
, PString
& type
, PString
& value
);
211 BOOL
ParseStruct(PXMLElement
* element
, PStringToString
& structDict
);
212 BOOL
ParseStruct(PXMLElement
* element
, PXMLRPCStructBase
& structData
);
213 BOOL
ParseArray(PXMLElement
* element
, PStringArray
& array
);
214 BOOL
ParseArray(PXMLElement
* element
, PArray
<PStringToString
> & array
);
215 BOOL
ParseArray(PXMLElement
* element
, PXMLRPCVariableBase
& array
);
217 // static functions for creating values
218 static PXMLElement
* CreateValueElement(PXMLElement
* element
);
219 static PXMLElement
* CreateScalar(const PString
& type
, const PString
& scalar
);
220 static PXMLElement
* CreateMember(const PString
& name
, PXMLElement
* value
);
222 static PXMLElement
* CreateScalar(const PString
& str
);
223 static PXMLElement
* CreateScalar(int value
);
224 static PXMLElement
* CreateScalar(double value
);
225 static PXMLElement
* CreateDateAndTime(const PTime
& time
);
226 static PXMLElement
* CreateBinary(const PBYTEArray
& data
);
228 static PXMLElement
* CreateStruct();
229 static PXMLElement
* CreateStruct(const PStringToString
& dict
);
230 static PXMLElement
* CreateStruct(const PStringToString
& dict
, const PString
& typeStr
);
231 static PXMLElement
* CreateStruct(const PXMLRPCStructBase
& structData
);
233 static PXMLElement
* CreateArray(const PStringArray
& array
);
234 static PXMLElement
* CreateArray(const PStringArray
& array
, const PString
& typeStr
);
235 static PXMLElement
* CreateArray(const PStringArray
& array
, const PStringArray
& types
);
236 static PXMLElement
* CreateArray(const PArray
<PStringToString
> & array
);
237 static PXMLElement
* CreateArray(const PXMLRPCVariableBase
& array
);
239 // helper functions for adding parameters
240 void AddParam(PXMLElement
* parm
);
241 void AddParam(const PString
& str
);
242 void AddParam(int value
);
243 void AddParam(double value
);
244 void AddParam(const PTime
& time
);
245 void AddParam(const PXMLRPCStructBase
& structData
);
246 void AddBinary(const PBYTEArray
& data
);
247 void AddStruct(const PStringToString
& dict
);
248 void AddStruct(const PStringToString
& dict
, const PString
& typeStr
);
249 void AddArray(const PStringArray
& array
);
250 void AddArray(const PStringArray
& array
, const PString
& typeStr
);
251 void AddArray(const PStringArray
& array
, const PStringArray
& types
);
252 void AddArray(const PArray
<PStringToString
> & array
);
255 PXMLElement
* params
;
261 /////////////////////////////////////////////////////////////////
263 class PXMLRPCVariableBase
: public PObject
{
264 PCLASSINFO(PXMLRPCVariableBase
, PObject
);
266 PXMLRPCVariableBase(const char * name
, const char * type
= NULL
);
269 const char * GetName() const { return name
; }
270 const char * GetType() const { return type
; }
272 virtual void Copy(const PXMLRPCVariableBase
& other
) = 0;
273 virtual PString
ToString(PINDEX i
) const;
274 virtual void FromString(PINDEX i
, const PString
& str
);
275 virtual PXMLRPCStructBase
* GetStruct(PINDEX i
) const;
276 virtual BOOL
IsArray() const;
277 virtual PINDEX
GetSize() const;
278 virtual BOOL
SetSize(PINDEX
);
280 PString
ToBase64(PAbstractArray
& data
) const;
281 void FromBase64(const PString
& str
, PAbstractArray
& data
);
288 PXMLRPCVariableBase(const PXMLRPCVariableBase
&) { }
292 class PXMLRPCArrayBase
: public PXMLRPCVariableBase
{
293 PCLASSINFO(PXMLRPCArrayBase
, PXMLRPCVariableBase
);
295 PXMLRPCArrayBase(PContainer
& array
, const char * name
, const char * type
);
296 PXMLRPCArrayBase
& operator=(const PXMLRPCArrayBase
&);
299 virtual void PrintOn(ostream
& strm
) const;
300 virtual void Copy(const PXMLRPCVariableBase
& other
);
301 virtual BOOL
IsArray() const;
302 virtual PINDEX
GetSize() const;
303 virtual BOOL
SetSize(PINDEX
);
310 class PXMLRPCArrayObjectsBase
: public PXMLRPCArrayBase
{
311 PCLASSINFO(PXMLRPCArrayObjectsBase
, PXMLRPCArrayBase
);
313 PXMLRPCArrayObjectsBase(PArrayObjects
& array
, const char * name
, const char * type
);
314 PXMLRPCArrayObjectsBase
& operator=(const PXMLRPCArrayObjectsBase
&);
317 virtual PString
ToString(PINDEX i
) const;
318 virtual void FromString(PINDEX i
, const PString
& str
);
319 virtual BOOL
SetSize(PINDEX
);
321 virtual PObject
* CreateObject() const = 0;
324 PArrayObjects
& array
;
328 class PXMLRPCStructBase
: public PObject
{
329 PCLASSINFO(PXMLRPCStructBase
, PObject
);
332 PXMLRPCStructBase
& operator=(const PXMLRPCStructBase
&);
334 PXMLRPCStructBase(const PXMLRPCStructBase
&) { }
337 void PrintOn(ostream
& strm
) const;
339 PINDEX
GetNumVariables() const { return variablesByOrder
.GetSize(); }
340 PXMLRPCVariableBase
& GetVariable(PINDEX idx
) const { return variablesByOrder
[idx
]; }
341 PXMLRPCVariableBase
* GetVariable(const char * name
) const { return variablesByName
.GetAt(name
); }
343 void AddVariable(PXMLRPCVariableBase
* var
);
344 static PXMLRPCStructBase
& GetInitialiser() { return *PAssertNULL(initialiserInstance
); }
347 void EndConstructor();
349 PList
<PXMLRPCVariableBase
> variablesByOrder
;
350 PDictionary
<PString
, PXMLRPCVariableBase
> variablesByName
;
352 PXMLRPCStructBase
* initialiserStack
;
353 static PMutex initialiserMutex
;
354 static PXMLRPCStructBase
* initialiserInstance
;
358 #define PXMLRPC_STRUCT_BEGIN(name) \
359 class name : public PXMLRPCStructBase { \
360 public: name() { EndConstructor(); } \
361 public: name(const name & other) { EndConstructor(); operator=(other); } \
362 public: name & operator=(const name & other) { PXMLRPCStructBase::operator=(other); return *this; }
364 #define PXMLRPC_VARIABLE_CLASS(base, type, variable, xmltype, init, extras) \
365 private: struct PXMLRPCVar_##variable : public PXMLRPCVariableBase { \
366 PXMLRPCVar_##variable() \
367 : PXMLRPCVariableBase(#variable, xmltype), \
368 instance(((base &)base::GetInitialiser()).variable) \
370 virtual void PrintOn (ostream & s) const { s << instance; } \
371 virtual void ReadFrom(istream & s) { s >> instance; } \
372 virtual void Copy(const PXMLRPCVariableBase & other) \
373 { instance = ((PXMLRPCVar_##variable &)other).instance; } \
376 } pxmlrpcvar_##variable
378 #define PXMLRPC_VARIABLE_CUSTOM(base, type, variable, xmltype, init, extras) \
379 public: type variable; \
380 PXMLRPC_VARIABLE_CLASS(base, type, variable, xmltype, init, extras)
382 #define PXMLRPC_ARRAY_CUSTOM(base, arraytype, basetype, variable, xmltype, par, extras) \
383 public: arraytype variable; \
384 private: struct PXMLRPCVar_##variable : public par { \
385 PXMLRPCVar_##variable() \
386 : par(((base &)base::GetInitialiser()).variable, #variable, xmltype), \
387 instance((arraytype &)array) \
390 arraytype & instance; \
391 } pxmlrpcvar_##variable
397 #define PXMLRPC_STRUCT_END() \
401 #define PXMLRPC_VARIABLE(base, type, variable, xmltype) \
402 PXMLRPC_VARIABLE_CUSTOM(base, type, variable, xmltype, ;, ;)
405 #define PXMLRPC_VARIABLE_INIT(base, type, variable, xmltype, init) \
406 PXMLRPC_VARIABLE_CUSTOM(base, type, variable, xmltype, instance=init;, ;)
409 #define PXMLRPC_STRING(base, type, variable) \
410 PXMLRPC_VARIABLE(base, type, variable, "string")
413 #define PXMLRPC_STRING_INIT(base, type, variable, init) \
414 PXMLRPC_VARIABLE_INIT(base, type, variable, "string", init)
417 #define PXMLRPC_INTEGER(base, type, variable) \
418 PXMLRPC_VARIABLE(base, type, variable, "int")
421 #define PXMLRPC_INTEGER_INIT(base, type, variable, init) \
422 PXMLRPC_VARIABLE_INIT(base, type, variable, "int", init)
425 #define PXMLRPC_BOOLEAN(base, type, variable) \
426 PXMLRPC_VARIABLE(base, type, variable, "boolean")
429 #define PXMLRPC_BOOLEAN_INIT(base, type, variable, init) \
430 PXMLRPC_VARIABLE_INIT(base, type, variable, "boolean", init)
433 #define PXMLRPC_DOUBLE(base, type, variable) \
434 PXMLRPC_VARIABLE(base, type, variable, "double")
437 #define PXMLRPC_DOUBLE_INIT(base, type, variable, init) \
438 PXMLRPC_VARIABLE_INIT(base, type, variable, "double", init)
441 #define PXMLRPC_DATETIME(base, type, variable) \
442 PXMLRPC_VARIABLE_CUSTOM(base, type, variable, "dateTime.iso8601", ;, \
443 PString ToString(PINDEX) const { return instance.AsString(PTime::ShortISO8601); } )
446 #define PXMLRPC_BINARY(base, type, variable) \
447 PXMLRPC_VARIABLE_CUSTOM(base, type, variable, "base64", ;, \
448 PString ToString(PINDEX) const { return ToBase64(instance); } \
449 void FromString(PINDEX, const PString & str) { FromBase64(str, instance); } )
452 #define PXMLRPC_STRUCT(base, type, variable) \
453 PXMLRPC_VARIABLE_CUSTOM(base, type, variable, "struct", ;, \
454 PXMLRPCStructBase * GetStruct(PINDEX) const { return &instance; } )
457 #define PXMLRPC_ARRAY(base, arraytype, basetype, variable, xmltype) \
458 PXMLRPC_ARRAY_CUSTOM(base, arraytype, basetype, variable, xmltype, PXMLRPCArrayObjectsBase, \
459 PObject * CreateObject() const { return new basetype; })
462 #define PXMLRPC_ARRAY_STRING(base, arraytype, basetype, variable) \
463 PXMLRPC_ARRAY(base, arraytype, basetype, variable, "string")
465 #define PXMLRPC_ARRAY_INTEGER(base, type, variable) \
466 PXMLRPC_ARRAY_CUSTOM(base, PScalarArray<type>, type, variable, "int", PXMLRPCArrayBase, \
467 PString ToString(PINDEX i) const { return PString(instance[i]); } \
468 void FromString(PINDEX i, const PString & str) { instance[i] = (type)str.AsInteger(); })
470 #define PXMLRPC_ARRAY_DOUBLE(base, type, variable) \
471 PXMLRPC_ARRAY_CUSTOM(base, PScalarArray<type>, type, variable, "double", PXMLRPCArrayBase, \
472 PString ToString(PINDEX i) const { return psprintf("%f", instance[i]); } \
473 void FromString(PINDEX i, const PString & str) { instance[i] = (type)str.AsReal(); })
475 #define PXMLRPC_ARRAY_STRUCT(base, type, variable) \
476 PXMLRPC_ARRAY_CUSTOM(base, PArray<type>, type, variable, "struct", PXMLRPCArrayObjectsBase, \
477 PXMLRPCStructBase * GetStruct(PINDEX i) const { return &instance[i]; } \
478 PObject * CreateObject() const { return new type; })
481 #define PXMLRPC_FUNC_NOARG_NOREPLY(name) \
482 BOOL name() { return MakeRequest(#name); }
485 #define PXMLRPC_FUNC_SINGLE_ARG(name, vartype, argtype) \
486 class name##_in : public PXMLRPCStructBase { \
487 public: name##_in(const argtype & var) : variable(var) { EndConstructor(); } \
488 vartype(name##_in, argtype, variable);
491 #define PXMLRPC_FUNC_MULTI_ARGS(name) \
492 PXMLRPC_STRUCT_BEGIN(name##_in)
498 #define PXMLRPC_FUNC_MULTI_REPLY(name) \
499 }; PXMLRPC_STRUCT_BEGIN(name##_out)
505 #define PXMLRPC_FUNC_NO_ARGS(name) \
507 BOOL name(name##_out & reply) \
508 { return MakeRequest(#name, name##_in(), reply); }
514 #define PXMLRPC_FUNC_STRUCT_ARG(name) \
516 class name##_in_carrier : public PXMLRPCStructBase { \
517 public: name##_in_carrier(const name##_in & var) : variable(var) { EndConstructor(); } \
518 private: struct var_class : public PXMLRPCVariableBase { \
519 var_class(const name##_in & var) \
520 : PXMLRPCVariableBase("variable", "struct"), instance(var) { } \
521 virtual void PrintOn (ostream & s) const { s << instance; } \
522 virtual PXMLRPCStructBase * GetStruct(PINDEX) const { return (PXMLRPCStructBase *)&instance; } \
523 virtual void Copy(const PXMLRPCVariableBase &) { } \
524 const name##_in & instance; \
527 BOOL name(const name##_in & args, name##_out & reply) \
528 { return MakeRequest(#name, name##_in_carrier(args), reply); }
534 #define PXMLRPC_FUNC_NORM_ARGS(name) \
536 BOOL name(const name##_in & args, name##_out & reply) \
537 { return MakeRequest(#name, args, reply); }
541 /////////////////////////////////////////////////////////////////