6 #include "xmlrpc-c/girerr.hpp"
8 #include "xmlrpc-c/girmem.hpp"
9 using girmem::autoObject;
10 using girmem::autoObjectPtr;
11 #include "xmlrpc-c/base.h"
12 #include "xmlrpc-c/base.hpp"
13 #include "env_wrap.hpp"
15 #include "xmlrpc-c/registry.hpp"
18 using namespace xmlrpc_c;
24 throwIfError(env_wrap const& env) {
26 if (env.env_c.fault_occurred)
27 throw(error(env.env_c.fault_string));
38 _help("No help is available for this method")
47 methodPtr::methodPtr(method * const methodP) {
54 methodPtr::operator->() const {
56 autoObject * const p(this->objectP);
57 return dynamic_cast<method *>(p);
62 defaultMethod::~defaultMethod() {}
66 defaultMethodPtr::defaultMethodPtr() {}
69 defaultMethodPtr::defaultMethodPtr(defaultMethod * const methodP) {
76 defaultMethodPtr::operator->() const {
78 autoObject * const p(this->objectP);
79 return dynamic_cast<defaultMethod *>(p);
85 defaultMethodPtr::get() const {
87 autoObject * const p(this->objectP);
88 return dynamic_cast<defaultMethod *>(p);
93 registry::registry() {
97 this->c_registryP = xmlrpc_registry_new(&env.env_c);
104 registry::~registry(void) {
106 xmlrpc_registry_free(this->c_registryP);
111 registryPtr::registryPtr() {}
115 registryPtr::registryPtr(registry * const registryP) {
116 this->point(registryP);
122 registryPtr::operator->() const {
124 autoObject * const p(this->objectP);
125 return dynamic_cast<registry *>(p);
131 registryPtr::get() const {
133 autoObject * const p(this->objectP);
134 return dynamic_cast<registry *>(p);
139 static xmlrpc_c::paramList
140 pListFromXmlrpcArray(xmlrpc_value * const arrayP) {
141 /*----------------------------------------------------------------------------
142 Convert an XML-RPC array in C (not C++) form to a parameter list object
143 that can be passed to a method execute method.
145 This is glue code to allow us to hook up C++ Xmlrpc-c code to
147 -----------------------------------------------------------------------------*/
150 XMLRPC_ASSERT_ARRAY_OK(arrayP);
152 unsigned int const arraySize = xmlrpc_array_size(&env.env_c, arrayP);
154 assert(!env.env_c.fault_occurred);
156 xmlrpc_c::paramList paramList(arraySize);
158 for (unsigned int i = 0; i < arraySize; ++i) {
159 xmlrpc_value * arrayItemP;
161 xmlrpc_array_read_item(&env.env_c, arrayP, i, &arrayItemP);
162 assert(!env.env_c.fault_occurred);
164 paramList.add(xmlrpc_c::value(arrayItemP));
166 xmlrpc_DECREF(arrayItemP);
173 static xmlrpc_value *
174 c_executeMethod(xmlrpc_env * const envP,
175 xmlrpc_value * const paramArrayP,
176 void * const methodPtr) {
177 /*----------------------------------------------------------------------------
178 This is a function designed to be called via a C registry to
179 execute an XML-RPC method, but use a C++ method object to do the
180 work. You register this function as the method function and a
181 pointer to the C++ method object as the method data in the C
184 If we had a pure C++ registry, this would be unnecessary.
186 Since we can't throw an error back to the C code, we catch anything
187 the XML-RPC method's execute() method throws, and any error we
188 encounter in processing the result it returns, and turn it into an
189 XML-RPC method failure. This will cause a leak if the execute()
190 method actually created a result, since it will not get destroyed.
191 -----------------------------------------------------------------------------*/
192 xmlrpc_c::method * const methodP =
193 static_cast<xmlrpc_c::method *>(methodPtr);
194 xmlrpc_c::paramList const paramList(pListFromXmlrpcArray(paramArrayP));
196 xmlrpc_value * retval;
199 xmlrpc_c::value result;
202 methodP->execute(paramList, &result);
203 } catch (xmlrpc_c::fault const& fault) {
204 xmlrpc_env_set_fault(envP, fault.getCode(),
205 fault.getDescription().c_str());
206 } catch (girerr::error const& error) {
207 xmlrpc_env_set_fault(envP, 0, error.what());
209 if (envP->fault_occurred)
212 retval = result.cValue();
214 xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR,
215 "Unexpected error executing the code for this "
216 "particular method, detected by the Xmlrpc-c "
217 "method registry code. The method did not "
218 "fail; rather, it did not complete at all.");
226 static xmlrpc_value *
227 c_executeDefaultMethod(xmlrpc_env * const envP,
228 const char * const , // host
229 const char * const methodName,
230 xmlrpc_value * const paramArrayP,
231 void * const methodPtr) {
232 /*----------------------------------------------------------------------------
233 This is a function designed to be called via a C registry to
234 execute an XML-RPC method, but use a C++ method object to do the
235 work. You register this function as the default method function and a
236 pointer to the C++ default method object as the method data in the C
239 If we had a pure C++ registry, this would be unnecessary.
241 Since we can't throw an error back to the C code, we catch anything
242 the XML-RPC method's execute() method throws, and any error we
243 encounter in processing the result it returns, and turn it into an
244 XML-RPC method failure. This will cause a leak if the execute()
245 method actually created a result, since it will not get destroyed.
246 -----------------------------------------------------------------------------*/
247 defaultMethod * const methodP =
248 static_cast<defaultMethod *>(methodPtr);
249 paramList const paramList(pListFromXmlrpcArray(paramArrayP));
251 xmlrpc_value * retval;
257 methodP->execute(methodName, paramList, &result);
258 } catch (xmlrpc_c::fault const& fault) {
259 xmlrpc_env_set_fault(envP, fault.getCode(),
260 fault.getDescription().c_str());
261 } catch (girerr::error const& error) {
262 xmlrpc_env_set_fault(envP, 0, error.what());
264 if (envP->fault_occurred)
267 retval = result.cValue();
269 xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR,
270 "Unexpected error executing the default "
271 "method code, detected by the Xmlrpc-c "
272 "method registry code. The method did not "
273 "fail; rather, it did not complete at all.");
282 registry::addMethod(string const name,
283 methodPtr const methodP) {
285 this->methodList.push_back(methodP);
289 xmlrpc_registry_add_method_w_doc(
290 &env.env_c, this->c_registryP, NULL,
291 name.c_str(), &c_executeMethod,
292 (void*) methodP.get(),
293 methodP->signature().c_str(), methodP->help().c_str());
301 registry::setDefaultMethod(defaultMethodPtr const methodP) {
303 this->defaultMethodP = methodP;
307 xmlrpc_registry_set_default_method(
308 &env.env_c, this->c_registryP,
309 &c_executeDefaultMethod, (void*) methodP.get());
317 registry::disableIntrospection() {
319 xmlrpc_registry_disable_introspection(this->c_registryP);
325 registry::processCall(string const& callXml,
326 string * const responseXmlP) const {
327 /*----------------------------------------------------------------------------
328 Process an XML-RPC call whose XML is 'callXml'.
330 Return the response XML as *responseXmlP.
332 If we are unable to execute the call, we throw an error. But if
333 the call executes and the method merely fails in an XML-RPC sense, we
334 don't. In that case, *responseXmlP indicates the failure.
335 -----------------------------------------------------------------------------*/
337 xmlrpc_mem_block * output;
339 // For the pure C++ version, this will have to parse 'callXml'
340 // into a method name and parameters, look up the method name in
341 // the registry, call the method's execute() method, then marshall
342 // the result into XML and return it as *responseXmlP. It will
343 // also have to execute system methods (e.g. introspection)
344 // itself. This will be more or less like what
345 // xmlrpc_registry_process_call() does.
347 output = xmlrpc_registry_process_call(
348 &env.env_c, this->c_registryP, NULL,
349 callXml.c_str(), callXml.length());
353 *responseXmlP = string(XMLRPC_MEMBLOCK_CONTENTS(char, output),
354 XMLRPC_MEMBLOCK_SIZE(char, output));
356 xmlrpc_mem_block_free(output);
360 registry::c_registry() const {
362 return this->c_registryP;