CMake/Utilities/cmxmlrpc/XmlRpcCpp.h
2005-02-22 13:08:27 -05:00

429 lines
14 KiB
C++

// -*- C++ -*- <-- an Emacs control
// Copyright information is at the bottom of the file.
//=========================================================================
// XML-RPC C++ API
//=========================================================================
#ifndef _XMLRPCCPP_H_
#define _XMLRPCCPP_H_ 1
// The C++ standard says we should either include <string.h> (which gets
// us the wrong header), or say 'using namespace std;' (which doesn't
// work with our version of g++). So this header name is technically wrong.
// Tell me what your compiler does; I can provide some autoconf magic to the
// Right Thing on most platforms.
//
// 2004.12.22 Bryan: This looks like a problem with whatever g++ he was
// using, so if anything, the special case should be for that. In any case,
// we've already added using namespace std to other files, without knowing
// there was an issue, so I'm just going to do the "using namespace"
// unconditionally and see who complains. If there are complaints, we can
// improve the documentation here.
//
// Formerly, the "using namespace std" was under
// "#if defined(__GNUC__) && (__GNUC__ >= 3)".
#include <string>
using namespace std;
#include <xmlrpc_config.h>
#include <xmlrpc.h>
#include <xmlrpc_client.h>
#include <xmlrpc_server.h>
#define XMLRPC_NO_ASSIGNMENT \
XMLRPC_FATAL_ERROR("Assignment operator not available"); return *this;
//=========================================================================
// XmlRpcFault
//=========================================================================
// A C++ exception class representing an XML-RPC fault.
class XmlRpcFault {
private:
xmlrpc_env mFault;
XmlRpcFault& operator= (const XmlRpcFault& f)
{ (void) f; XMLRPC_NO_ASSIGNMENT }
public:
XmlRpcFault (const XmlRpcFault &fault);
XmlRpcFault (const int faultCode, const string faultString);
XmlRpcFault (const xmlrpc_env *env);
~XmlRpcFault (void);
int getFaultCode (void) const;
string getFaultString (void) const;
xmlrpc_env *getFaultEnv (void);
};
inline int XmlRpcFault::getFaultCode (void) const {
return mFault.fault_code;
}
inline xmlrpc_env *XmlRpcFault::getFaultEnv (void) {
return &mFault;
}
//=========================================================================
// XmlRpcEnv
//=========================================================================
// This class can be used to wrap xmlrpc_env object. Use it as follows:
//
// XmlRpcEnv env;
// xmlrpc_parse_value(env, v, "(i)", &i);
// env.throwIfFaultOccurred();
class XmlRpcEnv {
private:
xmlrpc_env mEnv;
void throwMe (void) const;
XmlRpcEnv& operator= (const XmlRpcEnv& e)
{ (void) e; XMLRPC_NO_ASSIGNMENT }
public:
XmlRpcEnv (const XmlRpcEnv &env);
XmlRpcEnv (void) { xmlrpc_env_init(&mEnv); }
~XmlRpcEnv (void) { xmlrpc_env_clean(&mEnv); }
bool faultOccurred (void) const { return mEnv.fault_occurred; };
bool hasFaultOccurred (void) const { return faultOccurred(); };
/* hasFaultOccurred() is for backward compatibility.
faultOccurred() is a superior name for this.
*/
XmlRpcFault getFault (void) const;
void throwIfFaultOccurred (void) const;
operator xmlrpc_env * (void) { return &mEnv; }
};
inline void XmlRpcEnv::throwIfFaultOccurred (void) const {
if (faultOccurred())
throwMe();
}
//=========================================================================
// XmlRpcValue
//=========================================================================
// An object in this class is an XML-RPC value.
//
// We have a complex structure to allow C code mixed in with C++ code
// which uses this class to refer to the same XML-RPC value object.
// This is especially important because there aren't proper C++ facilities
// for much of Xmlrpc-c; you have to use the C facilities even if you'd
// rather use proper C++.
//
// The XmlRpcValue object internally represents the value as an
// xmlrpc_value. It hold one reference to the xmlrpc_value. Users
// of XmlRpcValue never see that xmlrpc_value, but C code can. the
// C code might create the xmlrpc_value and then bind it to an XmlRpcValue,
// or it might get the xmlrpc_value handle from the XmlRpcValue. Finally,
// C code can simply use the XmlRpcValue where an xmlrpc_value handle is
// required and it gets converted automatically.
//
// So reference counting for the xmlrpc_value is quite a nightmare.
class XmlRpcValue {
private:
xmlrpc_value *mValue;
public:
enum ReferenceBehavior {
MAKE_REFERENCE,
CONSUME_REFERENCE
};
typedef xmlrpc_int32 int32;
XmlRpcValue (void);
XmlRpcValue (xmlrpc_value *value,
ReferenceBehavior behavior = MAKE_REFERENCE);
XmlRpcValue (const XmlRpcValue& value);
~XmlRpcValue (void);
XmlRpcValue& operator= (const XmlRpcValue& value);
// Accessing the value's type (think of this as lightweight RTTI).
xmlrpc_type getType(void) const;
// We don't supply an automatic conversion operator--you need to say
// whether you want to make or borrow this object's reference.
// XXX - Is it really OK for these to be const?
xmlrpc_value *makeReference (void) const;
xmlrpc_value *borrowReference (void) const;
// Some static "constructor" functions.
static XmlRpcValue makeInt (const XmlRpcValue::int32 i);
static XmlRpcValue makeBool (const bool b);
static XmlRpcValue makeDouble (const double d);
static XmlRpcValue makeDateTime (const string& dateTime);
static XmlRpcValue makeString (const string& str);
static XmlRpcValue makeString (const char *const str);
static XmlRpcValue makeString (const char *const str, size_t len);
static XmlRpcValue makeArray (void);
static XmlRpcValue makeStruct (void);
static XmlRpcValue makeBase64 (const unsigned char *const data,
size_t len);
/*
// An interface to xmlrpc_build_value.
static XmlRpcValue buildValue (const char *const format, ...);
*/
// Some functions to get the underlying data.
// These will throw an XmlRpcFault if the data is the wrong type.
XmlRpcValue::int32 getInt (void) const;
bool getBool (void) const;
double getDouble (void) const;
string getRawDateTime (void) const;
string getString (void) const;
XmlRpcValue getArray (void) const;
XmlRpcValue getStruct (void) const;
// This returns an internal pointer which will become invalid when
// all references to the underlying value are destroyed.
void getBase64 (const unsigned char *& out_data,
size_t& out_len) const;
/*
// An interface to xmlrpc_parse_value.
void parseValue (const char *const format, ...);
*/
// Array functions. These will throw an XmlRpcFault if the value
// isn't an array.
size_t arraySize (void) const;
void arrayAppendItem (const XmlRpcValue& value);
XmlRpcValue arrayGetItem (int index) const;
// Struct functions. These will throw an XmlRpcFault if the value
// isn't a struct.
size_t structSize (void) const;
bool structHasKey (const string& key) const;
XmlRpcValue structGetValue (const string& key) const;
void structSetValue (const string& key, const XmlRpcValue& value);
void structGetKeyAndValue (const int index,
string& out_key,
XmlRpcValue& out_value) const;
};
inline XmlRpcValue::XmlRpcValue (xmlrpc_value *value,
ReferenceBehavior behavior)
{
mValue = value;
if (behavior == MAKE_REFERENCE)
xmlrpc_INCREF(value);
}
inline XmlRpcValue::XmlRpcValue (const XmlRpcValue& value) {
mValue = value.mValue;
xmlrpc_INCREF(mValue);
}
inline XmlRpcValue::~XmlRpcValue (void) {
xmlrpc_DECREF(mValue);
}
inline XmlRpcValue& XmlRpcValue::operator= (const XmlRpcValue& value) {
// Must increment before we decrement, in case of assignment to self.
xmlrpc_INCREF(value.mValue);
xmlrpc_DECREF(mValue);
mValue = value.mValue;
return *this;
}
inline xmlrpc_type XmlRpcValue::getType (void) const {
return xmlrpc_value_type(mValue);
}
inline xmlrpc_value *XmlRpcValue::makeReference (void) const {
xmlrpc_INCREF(mValue);
return mValue;
}
inline xmlrpc_value *XmlRpcValue::borrowReference (void) const {
return mValue;
}
//=========================================================================
// XmlRpcClient
//=========================================================================
class XmlRpcClient {
private:
string mServerUrl;
public:
static void Initialize (string appname, string appversion);
static void Terminate (void);
XmlRpcClient (const string& server_url) : mServerUrl(server_url) {}
~XmlRpcClient (void) {}
XmlRpcClient (const XmlRpcClient& client);
XmlRpcClient& operator= (const XmlRpcClient& client);
XmlRpcValue call (string method_name, XmlRpcValue param_array);
void call_asynch (string method_name,
XmlRpcValue param_array,
xmlrpc_response_handler callback,
void* user_data);
void event_loop_asynch (unsigned long milliseconds);
};
inline void XmlRpcClient::call_asynch(string method_name,
XmlRpcValue param_array,
xmlrpc_response_handler callback,
void* user_data)
{
xmlrpc_client_call_asynch_params(
mServerUrl.c_str(),
method_name.c_str(),
callback,
user_data,
param_array.borrowReference());
}
inline void XmlRpcClient::event_loop_asynch(unsigned long milliseconds)
{
xmlrpc_client_event_loop_finish_asynch_timeout(milliseconds);
}
//=========================================================================
// XmlRpcClient Methods
//=========================================================================
// These are inline for now, so we don't need to screw with linker issues
// and build a separate client library.
inline XmlRpcClient::XmlRpcClient (const XmlRpcClient& client)
: mServerUrl(client.mServerUrl)
{
}
inline XmlRpcClient& XmlRpcClient::operator= (const XmlRpcClient& client) {
if (this != &client)
mServerUrl = client.mServerUrl;
return *this;
}
inline void XmlRpcClient::Initialize (string appname, string appversion) {
xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS,
appname.c_str(),
appversion.c_str());
}
inline void XmlRpcClient::Terminate (void) {
xmlrpc_client_cleanup();
}
inline XmlRpcValue XmlRpcClient::call (string method_name,
XmlRpcValue param_array)
{
XmlRpcEnv env;
xmlrpc_value *result =
xmlrpc_client_call_params(env,
mServerUrl.c_str(),
method_name.c_str(),
param_array.borrowReference());
env.throwIfFaultOccurred();
return XmlRpcValue(result, XmlRpcValue::CONSUME_REFERENCE);
}
//=========================================================================
// XmlRpcGenSrv
//=========================================================================
class XmlRpcGenSrv {
private:
xmlrpc_registry* mRegistry;
xmlrpc_mem_block* alloc (XmlRpcEnv& env, const string& body) const;
public:
XmlRpcGenSrv (int flags);
~XmlRpcGenSrv (void);
xmlrpc_registry* getRegistry (void) const;
XmlRpcGenSrv& addMethod (const string& name,
xmlrpc_method method,
void *data);
XmlRpcGenSrv& addMethod (const string& name,
xmlrpc_method method,
void* data,
const string& signature,
const string& help);
string handle (const string& body) const;
};
inline XmlRpcGenSrv::XmlRpcGenSrv (int flags) {
XmlRpcEnv env;
if (flags == flags){};
mRegistry = xmlrpc_registry_new (env);
env.throwIfFaultOccurred();
}
inline XmlRpcGenSrv::~XmlRpcGenSrv (void) {
xmlrpc_registry_free (mRegistry);
}
inline xmlrpc_registry* XmlRpcGenSrv::getRegistry () const {
return mRegistry;
}
#undef XMLRPC_NO_ASSIGNMENT
// Copyright (C) 2001 by Eric Kidd. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. The name of the author may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
#endif /* _XMLRPCCPP_H_ */