pxmlrpc.h

Go to the documentation of this file.
00001 /*
00002  * pxmlrpc.h
00003  *
00004  * XML/RPC support
00005  *
00006  * Portable Windows Library
00007  *
00008  * Copyright (c) 2002 Equivalence Pty. Ltd.
00009  *
00010  * The contents of this file are subject to the Mozilla Public License
00011  * Version 1.0 (the "License"); you may not use this file except in
00012  * compliance with the License. You may obtain a copy of the License at
00013  * http://www.mozilla.org/MPL/
00014  *
00015  * Software distributed under the License is distributed on an "AS IS"
00016  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
00017  * the License for the specific language governing rights and limitations
00018  * under the License.
00019  *
00020  * The Original Code is Portable Windows Library.
00021  *
00022  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
00023  *
00024  * Contributor(s): ______________________________________.
00025  *
00026  * $Log: pxmlrpc.h,v $
00027  * Revision 1.20  2004/05/17 06:05:20  csoutheren
00028  * Changed "make docs" to use doxygen
00029  * Added new config file and main page
00030  *
00031  * Revision 1.19  2003/04/15 07:08:36  robertj
00032  * Changed read and write from streams for base array classes so operates in
00033  *   the same way for both PIntArray and PArray<int> etc
00034  *
00035  * Revision 1.18  2003/04/15 03:00:41  robertj
00036  * Added array support to XML/RPC
00037  * Fixed XML/RPC parsing when lots of white space in raw XML, caused by
00038  *   big fix to base XML parser not returning internal data elements.
00039  *
00040  * Revision 1.17  2003/01/28 05:08:07  robertj
00041  * Fixed copy constructor on function arguments and return value
00042  *
00043  * Revision 1.16  2002/12/16 06:57:15  robertj
00044  * Added ability to specify certain elemets (by name) that are exempt from
00045  *   the indent formatting. Useful for XML/RPC where leading white space is
00046  *   not ignored by all servers.
00047  * Improved the macros for defining RPC functions.
00048  *
00049  * Revision 1.15  2002/12/13 01:04:56  robertj
00050  * Added copy constructor and assignment operator to XML/RPC structs
00051  *
00052  * Revision 1.14  2002/12/10 04:44:43  robertj
00053  * Added support in PTime for ISO 8601 format.
00054  *
00055  * Revision 1.13  2002/12/09 04:06:18  robertj
00056  * Added macros for defining multi-argument functions
00057  *
00058  * Revision 1.12  2002/12/04 02:09:26  robertj
00059  * Changed macro name prefix to PXMLRPC
00060  *
00061  * Revision 1.11  2002/12/04 00:31:13  robertj
00062  * Fixed GNU compatibility
00063  *
00064  * Revision 1.10  2002/12/04 00:15:56  robertj
00065  * Large enhancement to create automatically encoding and decoding structures
00066  *   using macros to build a class.
00067  *
00068  * Revision 1.9  2002/11/06 22:47:24  robertj
00069  * Fixed header comment (copyright etc)
00070  *
00071  * Revision 1.8  2002/10/02 08:54:34  craigs
00072  * Added support for XMLRPC server
00073  *
00074  * Revision 1.7  2002/09/16 01:08:59  robertj
00075  * Added #define so can select if #pragma interface/implementation is used on
00076  *   platform basis (eg MacOS) rather than compiler, thanks Robert Monaghan.
00077  *
00078  * Revision 1.6  2002/08/13 03:02:07  robertj
00079  * Removed previous fix for memory leak, as object was already deleted.
00080  *
00081  * Revision 1.5  2002/08/13 01:55:00  craigs
00082  * Fixed memory leak on PXMLRPCRequest class
00083  *
00084  * Revision 1.4  2002/08/06 01:04:03  robertj
00085  * Fixed missing pragma interface/implementation
00086  *
00087  * Revision 1.3  2002/07/12 05:51:14  craigs
00088  * Added structs to XMLRPC response types
00089  *
00090  * Revision 1.2  2002/03/27 00:50:44  craigs
00091  * Fixed problems with parsing faults and creating structs
00092  *
00093  * Revision 1.1  2002/03/26 07:06:50  craigs
00094  * Initial version
00095  *
00096  */
00097 
00098 #ifndef _PXMLRPC_H
00099 #define _PXMLRPC_H
00100 
00101 #ifdef P_USE_PRAGMA
00102 #pragma interface
00103 #endif
00104 
00105 #include <ptclib/pxml.h>
00106 #include <ptclib/url.h>
00107 
00108 
00109 class PXMLRPCBlock;
00110 class PXMLRPCVariableBase;
00111 class PXMLRPCStructBase;
00112 
00113 
00115 
00116 class PXMLRPC : public PObject
00117 {
00118   PCLASSINFO(PXMLRPC, PObject);
00119   public:
00120     enum {
00121       CannotCreateRequestXML          = 100,
00122       CannotParseResponseXML,
00123       CannotParseRequestXML,
00124       HTTPPostFailed,
00125       CannotReadResponseContentBody,
00126       ResponseRootNotMethodResponse,
00127       ResponseEmpty,
00128       ResponseUnknownFormat,
00129       ParamNotValue,
00130       ScalarWithoutElement,
00131       ParamNotStruct,
00132       MemberIncomplete,
00133       MemberUnnamed,
00134       FaultyFault,
00135       RequestHasWrongDocumentType,
00136       RequestHasNoMethodName,
00137       RequestHasNoParms,
00138       MethodNameIsEmpty,
00139       UnknownMethod,
00140       ParamNotArray,
00141 
00142       UserFault                       = 1000,
00143     };
00144 
00145     PXMLRPC(
00146       const PURL & url,
00147       unsigned options = 0
00148     );
00149 
00150     void SetTimeout(const PTimeInterval & _timeout) { timeout = _timeout; }
00151 
00152     BOOL MakeRequest(const PString & method);
00153     BOOL MakeRequest(const PString & method,  PXMLRPCBlock & response);
00154     BOOL MakeRequest(PXMLRPCBlock & request, PXMLRPCBlock & response);
00155     BOOL MakeRequest(const PString & method, const PXMLRPCStructBase & args, PXMLRPCStructBase & reply);
00156 
00157     PString GetFaultText() const { return faultText; }
00158     PINDEX  GetFaultCode() const { return faultCode; }
00159 
00160     static BOOL    ISO8601ToPTime(const PString & iso8601, PTime & val, int tz = PTime::GMT);
00161     static PString PTimeToISO8601(const PTime & val);
00162 
00163   protected:
00164     BOOL PerformRequest(PXMLRPCBlock & request, PXMLRPCBlock & response);
00165 
00166     PURL          url;
00167     PINDEX        faultCode;
00168     PString       faultText;
00169     PTimeInterval timeout;
00170     unsigned      options;
00171 };
00172 
00174 
00175 class PXMLRPCBlock : public PXML
00176 {
00177   PCLASSINFO(PXMLRPCBlock, PXML);
00178   public:
00179     PXMLRPCBlock();
00180     PXMLRPCBlock(const PString & method);
00181     PXMLRPCBlock(const PString & method, const PXMLRPCStructBase & structData);
00182 
00183     BOOL Load(const PString & str);
00184 
00185     PXMLElement * GetParams();
00186     PXMLElement * GetParam(PINDEX idx) const;
00187     PINDEX GetParamCount() const;
00188 
00189     // used when used as a response
00190     PINDEX  GetFaultCode() const                     { return faultCode; }
00191     PString GetFaultText() const                     { return faultText; }
00192     void SetFault(PINDEX code, const PString & text) { faultCode = code; faultText = text; }
00193     BOOL ValidateResponse();
00194 
00195     // helper functions for getting parameters
00196     BOOL GetParams(PXMLRPCStructBase & data);
00197     BOOL GetParam(PINDEX idx, PString & type, PString & result);
00198     BOOL GetExpectedParam(PINDEX idx, const PString & expectedType, PString & value);
00199 
00200     BOOL GetParam(PINDEX idx, PString & result);
00201     BOOL GetParam(PINDEX idx, int & result);
00202     BOOL GetParam(PINDEX idx, double & result);
00203     BOOL GetParam(PINDEX idx, PTime & result, int tz = PTime::GMT);
00204     BOOL GetParam(PINDEX idx, PStringToString & result);
00205     BOOL GetParam(PINDEX idx, PXMLRPCStructBase & result);
00206     BOOL GetParam(PINDEX idx, PStringArray & result);
00207     BOOL GetParam(PINDEX idx, PArray<PStringToString> & result);
00208 
00209     // static functions for parsing values
00210     BOOL ParseScalar(PXMLElement * element, PString & type, PString & value);
00211     BOOL ParseStruct(PXMLElement * element, PStringToString & structDict);
00212     BOOL ParseStruct(PXMLElement * element, PXMLRPCStructBase & structData);
00213     BOOL ParseArray(PXMLElement * element, PStringArray & array);
00214     BOOL ParseArray(PXMLElement * element, PArray<PStringToString> & array);
00215     BOOL ParseArray(PXMLElement * element, PXMLRPCVariableBase & array);
00216 
00217     // static functions for creating values
00218     static PXMLElement * CreateValueElement(PXMLElement * element);
00219     static PXMLElement * CreateScalar(const PString & type, const PString & scalar);
00220     static PXMLElement * CreateMember(const PString & name, PXMLElement * value);
00221 
00222     static PXMLElement * CreateScalar(const PString & str);
00223     static PXMLElement * CreateScalar(int value);
00224     static PXMLElement * CreateScalar(double value);
00225     static PXMLElement * CreateDateAndTime(const PTime & time);
00226     static PXMLElement * CreateBinary(const PBYTEArray & data);
00227 
00228     static PXMLElement * CreateStruct();
00229     static PXMLElement * CreateStruct(const PStringToString & dict);
00230     static PXMLElement * CreateStruct(const PStringToString & dict, const PString & typeStr);
00231     static PXMLElement * CreateStruct(const PXMLRPCStructBase & structData);
00232 
00233     static PXMLElement * CreateArray(const PStringArray & array);
00234     static PXMLElement * CreateArray(const PStringArray & array, const PString & typeStr);
00235     static PXMLElement * CreateArray(const PStringArray & array, const PStringArray & types);
00236     static PXMLElement * CreateArray(const PArray<PStringToString> & array);
00237     static PXMLElement * CreateArray(const PXMLRPCVariableBase & array);
00238 
00239     // helper functions for adding parameters
00240     void AddParam(PXMLElement * parm);
00241     void AddParam(const PString & str);
00242     void AddParam(int value);
00243     void AddParam(double value);
00244     void AddParam(const PTime & time);
00245     void AddParam(const PXMLRPCStructBase & structData);
00246     void AddBinary(const PBYTEArray & data);
00247     void AddStruct(const PStringToString & dict);
00248     void AddStruct(const PStringToString & dict, const PString & typeStr);
00249     void AddArray(const PStringArray & array);
00250     void AddArray(const PStringArray & array, const PString & typeStr);
00251     void AddArray(const PStringArray & array, const PStringArray & types);
00252     void AddArray(const PArray<PStringToString> & array);
00253 
00254   protected:
00255     PXMLElement * params;
00256     PString faultText;
00257     PINDEX  faultCode;
00258 };
00259 
00260 
00262 
00263 class PXMLRPCVariableBase : public PObject {
00264     PCLASSINFO(PXMLRPCVariableBase, PObject);
00265   protected:
00266     PXMLRPCVariableBase(const char * name, const char * type = NULL);
00267 
00268   public:
00269     const char * GetName() const { return name; }
00270     const char * GetType() const { return type; }
00271 
00272     virtual void Copy(const PXMLRPCVariableBase & other) = 0;
00273     virtual PString ToString(PINDEX i) const;
00274     virtual void FromString(PINDEX i, const PString & str);
00275     virtual PXMLRPCStructBase * GetStruct(PINDEX i) const;
00276     virtual BOOL IsArray() const;
00277     virtual PINDEX GetSize() const;
00278     virtual BOOL SetSize(PINDEX);
00279 
00280     PString ToBase64(PAbstractArray & data) const;
00281     void FromBase64(const PString & str, PAbstractArray & data);
00282 
00283   protected:
00284     const char * name;
00285     const char * type;
00286 
00287   private:
00288     PXMLRPCVariableBase(const PXMLRPCVariableBase &) { }
00289 };
00290 
00291 
00292 class PXMLRPCArrayBase : public PXMLRPCVariableBase {
00293     PCLASSINFO(PXMLRPCArrayBase, PXMLRPCVariableBase);
00294   protected:
00295     PXMLRPCArrayBase(PContainer & array, const char * name, const char * type);
00296     PXMLRPCArrayBase & operator=(const PXMLRPCArrayBase &);
00297 
00298   public:
00299     virtual void PrintOn(ostream & strm) const;
00300     virtual void Copy(const PXMLRPCVariableBase & other);
00301     virtual BOOL IsArray() const;
00302     virtual PINDEX GetSize() const;
00303     virtual BOOL SetSize(PINDEX);
00304 
00305   protected:
00306     PContainer & array;
00307 };
00308 
00309 
00310 class PXMLRPCArrayObjectsBase : public PXMLRPCArrayBase {
00311     PCLASSINFO(PXMLRPCArrayObjectsBase, PXMLRPCArrayBase);
00312   protected:
00313     PXMLRPCArrayObjectsBase(PArrayObjects & array, const char * name, const char * type);
00314     PXMLRPCArrayObjectsBase & operator=(const PXMLRPCArrayObjectsBase &);
00315 
00316   public:
00317     virtual PString ToString(PINDEX i) const;
00318     virtual void FromString(PINDEX i, const PString & str);
00319     virtual BOOL SetSize(PINDEX);
00320 
00321     virtual PObject * CreateObject() const = 0;
00322 
00323   protected:
00324     PArrayObjects & array;
00325 };
00326 
00327 
00328 class PXMLRPCStructBase : public PObject {
00329     PCLASSINFO(PXMLRPCStructBase, PObject);
00330   protected:
00331     PXMLRPCStructBase();
00332     PXMLRPCStructBase & operator=(const PXMLRPCStructBase &);
00333   private:
00334     PXMLRPCStructBase(const PXMLRPCStructBase &) { }
00335 
00336   public:
00337     void PrintOn(ostream & strm) const;
00338 
00339     PINDEX GetNumVariables() const { return variablesByOrder.GetSize(); }
00340     PXMLRPCVariableBase & GetVariable(PINDEX idx) const { return variablesByOrder[idx]; }
00341     PXMLRPCVariableBase * GetVariable(const char * name) const { return variablesByName.GetAt(name); }
00342 
00343     void AddVariable(PXMLRPCVariableBase * var);
00344     static PXMLRPCStructBase & GetInitialiser() { return *PAssertNULL(initialiserInstance); }
00345 
00346   protected:
00347     void EndConstructor();
00348 
00349     PList<PXMLRPCVariableBase>                variablesByOrder;
00350     PDictionary<PString, PXMLRPCVariableBase> variablesByName;
00351 
00352     PXMLRPCStructBase        * initialiserStack;
00353     static PMutex              initialiserMutex;
00354     static PXMLRPCStructBase * initialiserInstance;
00355 };
00356 
00357 
00358 #define PXMLRPC_STRUCT_BEGIN(name) \
00359   class name : public PXMLRPCStructBase { \
00360     public: name() { EndConstructor(); } \
00361     public: name(const name & other) { EndConstructor(); operator=(other); } \
00362     public: name & operator=(const name & other) { PXMLRPCStructBase::operator=(other); return *this; }
00363 
00364 #define PXMLRPC_VARIABLE_CLASS(base, type, variable, xmltype, init, extras) \
00365     private: struct PXMLRPCVar_##variable : public PXMLRPCVariableBase { \
00366       PXMLRPCVar_##variable() \
00367         : PXMLRPCVariableBase(#variable, xmltype), \
00368           instance(((base &)base::GetInitialiser()).variable) \
00369         { init } \
00370       virtual void PrintOn (ostream & s) const { s << instance; } \
00371       virtual void ReadFrom(istream & s)       { s >> instance; } \
00372       virtual void Copy(const PXMLRPCVariableBase & other) \
00373                     { instance = ((PXMLRPCVar_##variable &)other).instance; } \
00374       extras \
00375       type & instance; \
00376     } pxmlrpcvar_##variable
00377 
00378 #define PXMLRPC_VARIABLE_CUSTOM(base, type, variable, xmltype, init, extras) \
00379     public: type variable; \
00380     PXMLRPC_VARIABLE_CLASS(base, type, variable, xmltype, init, extras)
00381 
00382 #define PXMLRPC_ARRAY_CUSTOM(base, arraytype, basetype, variable, xmltype, par, extras) \
00383     public: arraytype variable; \
00384     private: struct PXMLRPCVar_##variable : public par { \
00385       PXMLRPCVar_##variable() \
00386         : par(((base &)base::GetInitialiser()).variable, #variable, xmltype), \
00387           instance((arraytype &)array) \
00388         { } \
00389       extras \
00390       arraytype & instance; \
00391     } pxmlrpcvar_##variable
00392 #ifdef DOCPLUSPLUS
00393 }
00394 #endif
00395 
00396 
00397 #define PXMLRPC_STRUCT_END() \
00398   };
00399 
00400 
00401 #define PXMLRPC_VARIABLE(base, type, variable, xmltype) \
00402         PXMLRPC_VARIABLE_CUSTOM(base, type, variable, xmltype, ;, ;)
00403 
00404 
00405 #define PXMLRPC_VARIABLE_INIT(base, type, variable, xmltype, init) \
00406         PXMLRPC_VARIABLE_CUSTOM(base, type, variable, xmltype, instance=init;, ;)
00407 
00408 
00409 #define PXMLRPC_STRING(base, type, variable) \
00410         PXMLRPC_VARIABLE(base, type, variable, "string")
00411 
00412 
00413 #define PXMLRPC_STRING_INIT(base, type, variable, init) \
00414         PXMLRPC_VARIABLE_INIT(base, type, variable, "string", init)
00415 
00416 
00417 #define PXMLRPC_INTEGER(base, type, variable) \
00418         PXMLRPC_VARIABLE(base, type, variable, "int")
00419 
00420 
00421 #define PXMLRPC_INTEGER_INIT(base, type, variable, init) \
00422         PXMLRPC_VARIABLE_INIT(base, type, variable, "int", init)
00423 
00424 
00425 #define PXMLRPC_BOOLEAN(base, type, variable) \
00426         PXMLRPC_VARIABLE(base, type, variable, "boolean")
00427 
00428 
00429 #define PXMLRPC_BOOLEAN_INIT(base, type, variable, init) \
00430         PXMLRPC_VARIABLE_INIT(base, type, variable, "boolean", init)
00431 
00432 
00433 #define PXMLRPC_DOUBLE(base, type, variable) \
00434         PXMLRPC_VARIABLE(base, type, variable, "double")
00435 
00436 
00437 #define PXMLRPC_DOUBLE_INIT(base, type, variable, init) \
00438         PXMLRPC_VARIABLE_INIT(base, type, variable, "double", init)
00439 
00440 
00441 #define PXMLRPC_DATETIME(base, type, variable) \
00442         PXMLRPC_VARIABLE_CUSTOM(base, type, variable, "dateTime.iso8601", ;, \
00443                     PString ToString(PINDEX) const { return instance.AsString(PTime::ShortISO8601); } )
00444 
00445 
00446 #define PXMLRPC_BINARY(base, type, variable) \
00447         PXMLRPC_VARIABLE_CUSTOM(base, type, variable, "base64", ;, \
00448                     PString ToString(PINDEX) const { return ToBase64(instance); } \
00449                     void FromString(PINDEX, const PString & str) { FromBase64(str, instance); } )
00450 
00451 
00452 #define PXMLRPC_STRUCT(base, type, variable) \
00453         PXMLRPC_VARIABLE_CUSTOM(base, type, variable, "struct", ;, \
00454                     PXMLRPCStructBase * GetStruct(PINDEX) const { return &instance; } )
00455 
00456 
00457 #define PXMLRPC_ARRAY(base, arraytype, basetype, variable, xmltype) \
00458         PXMLRPC_ARRAY_CUSTOM(base, arraytype, basetype, variable, xmltype, PXMLRPCArrayObjectsBase, \
00459                     PObject * CreateObject() const { return new basetype; })
00460 
00461 
00462 #define PXMLRPC_ARRAY_STRING(base, arraytype, basetype, variable) \
00463         PXMLRPC_ARRAY(base, arraytype, basetype, variable, "string")
00464 
00465 #define PXMLRPC_ARRAY_INTEGER(base, type, variable) \
00466         PXMLRPC_ARRAY_CUSTOM(base, PScalarArray<type>, type, variable, "int", PXMLRPCArrayBase, \
00467                     PString ToString(PINDEX i) const { return PString(instance[i]); } \
00468                     void FromString(PINDEX i, const PString & str) { instance[i] = (type)str.AsInteger(); })
00469 
00470 #define PXMLRPC_ARRAY_DOUBLE(base, type, variable) \
00471         PXMLRPC_ARRAY_CUSTOM(base, PScalarArray<type>, type, variable, "double", PXMLRPCArrayBase, \
00472                     PString ToString(PINDEX i) const { return psprintf("%f", instance[i]); } \
00473                     void FromString(PINDEX i, const PString & str) { instance[i] = (type)str.AsReal(); })
00474 
00475 #define PXMLRPC_ARRAY_STRUCT(base, type, variable) \
00476         PXMLRPC_ARRAY_CUSTOM(base, PArray<type>, type, variable, "struct", PXMLRPCArrayObjectsBase, \
00477                              PXMLRPCStructBase * GetStruct(PINDEX i) const { return &instance[i]; } \
00478                              PObject * CreateObject() const { return new type; })
00479 
00480 
00481 #define PXMLRPC_FUNC_NOARG_NOREPLY(name) \
00482   BOOL name() { return MakeRequest(#name); }
00483 
00484 
00485 #define PXMLRPC_FUNC_SINGLE_ARG(name, vartype, argtype) \
00486   class name##_in : public PXMLRPCStructBase { \
00487     public: name##_in(const argtype & var) : variable(var) { EndConstructor(); } \
00488         vartype(name##_in, argtype, variable);
00489 
00490 
00491 #define PXMLRPC_FUNC_MULTI_ARGS(name) \
00492   PXMLRPC_STRUCT_BEGIN(name##_in)
00493 
00494 
00495 #ifdef DOCPLUSPLUS
00496 {
00497 #endif
00498 #define PXMLRPC_FUNC_MULTI_REPLY(name) \
00499   }; PXMLRPC_STRUCT_BEGIN(name##_out)
00500 
00501 
00502 #ifdef DOCPLUSPLUS
00503 {
00504 #endif
00505 #define PXMLRPC_FUNC_NO_ARGS(name) \
00506   }; \
00507   BOOL name(name##_out & reply) \
00508     { return MakeRequest(#name, name##_in(), reply); }
00509 
00510 
00511 #ifdef DOCPLUSPLUS
00512 {
00513 #endif
00514 #define PXMLRPC_FUNC_STRUCT_ARG(name) \
00515   }; \
00516   class name##_in_carrier : public PXMLRPCStructBase { \
00517     public: name##_in_carrier(const name##_in & var) : variable(var) { EndConstructor(); } \
00518     private: struct var_class : public PXMLRPCVariableBase { \
00519       var_class(const name##_in & var) \
00520         : PXMLRPCVariableBase("variable", "struct"), instance(var) { } \
00521       virtual void PrintOn (ostream & s) const { s << instance; } \
00522       virtual PXMLRPCStructBase * GetStruct(PINDEX) const { return (PXMLRPCStructBase *)&instance; } \
00523       virtual void Copy(const PXMLRPCVariableBase &) { } \
00524       const name##_in & instance; \
00525     } variable; \
00526   }; \
00527   BOOL name(const name##_in & args, name##_out & reply) \
00528     { return MakeRequest(#name, name##_in_carrier(args), reply); }
00529 
00530 
00531 #ifdef DOCPLUSPLUS
00532 {
00533 #endif
00534 #define PXMLRPC_FUNC_NORM_ARGS(name) \
00535   }; \
00536   BOOL name(const name##_in & args, name##_out & reply) \
00537     { return MakeRequest(#name, args, reply); }
00538 
00539 
00540 
00542 
00543 
00544 #endif

Generated on Fri Mar 7 06:25:02 2008 for PTLib by  doxygen 1.5.1