initial load of upstream version 1.06.32
[xmlrpc-c] / src / cpp / registry.cpp
1 #include <cassert>
2 #include <string>
3 #include <memory>
4 #include <algorithm>
5
6 #include "xmlrpc-c/girerr.hpp"
7 using girerr::error;
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"
14
15 #include "xmlrpc-c/registry.hpp"
16
17 using namespace std;
18 using namespace xmlrpc_c;
19
20
21 namespace {
22
23 void
24 throwIfError(env_wrap const& env) {
25
26     if (env.env_c.fault_occurred)
27         throw(error(env.env_c.fault_string));
28 }
29
30
31 } // namespace
32
33 namespace xmlrpc_c {
34
35
36 method::method() : 
37         _signature("?"),
38         _help("No help is available for this method")
39         {};
40
41
42
43 method::~method() {}
44
45
46
47 methodPtr::methodPtr(method * const methodP) {
48     this->point(methodP);
49 }
50
51
52
53 method *
54 methodPtr::operator->() const {
55
56     autoObject * const p(this->objectP);
57     return dynamic_cast<method *>(p);
58 }
59
60
61
62 defaultMethod::~defaultMethod() {}
63
64
65
66 defaultMethodPtr::defaultMethodPtr() {}
67
68
69 defaultMethodPtr::defaultMethodPtr(defaultMethod * const methodP) {
70     this->point(methodP);
71 }
72
73
74
75 defaultMethod *
76 defaultMethodPtr::operator->() const {
77
78     autoObject * const p(this->objectP);
79     return dynamic_cast<defaultMethod *>(p);
80 }
81
82
83
84 defaultMethod *
85 defaultMethodPtr::get() const {
86
87     autoObject * const p(this->objectP);
88     return dynamic_cast<defaultMethod *>(p);
89 }
90
91
92
93 registry::registry() {
94
95     env_wrap env;
96
97     this->c_registryP = xmlrpc_registry_new(&env.env_c);
98
99     throwIfError(env);
100 }
101
102
103
104 registry::~registry(void) {
105
106     xmlrpc_registry_free(this->c_registryP);
107 }
108
109
110
111 registryPtr::registryPtr() {}
112
113
114
115 registryPtr::registryPtr(registry * const registryP) {
116     this->point(registryP);
117 }
118
119
120
121 registry *
122 registryPtr::operator->() const {
123
124     autoObject * const p(this->objectP);
125     return dynamic_cast<registry *>(p);
126 }
127
128
129
130 registry *
131 registryPtr::get() const {
132
133     autoObject * const p(this->objectP);
134     return dynamic_cast<registry *>(p);
135 }
136
137
138
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.
144
145    This is glue code to allow us to hook up C++ Xmlrpc-c code to 
146    C Xmlrpc-c code.
147 -----------------------------------------------------------------------------*/
148     env_wrap env;
149
150     XMLRPC_ASSERT_ARRAY_OK(arrayP);
151
152     unsigned int const arraySize = xmlrpc_array_size(&env.env_c, arrayP);
153
154     assert(!env.env_c.fault_occurred);
155
156     xmlrpc_c::paramList paramList(arraySize);
157     
158     for (unsigned int i = 0; i < arraySize; ++i) {
159         xmlrpc_value * arrayItemP;
160
161         xmlrpc_array_read_item(&env.env_c, arrayP, i, &arrayItemP);
162         assert(!env.env_c.fault_occurred);
163
164         paramList.add(xmlrpc_c::value(arrayItemP));
165         
166         xmlrpc_DECREF(arrayItemP);
167     }
168     return paramList;
169 }
170
171
172
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
182    registry.
183
184    If we had a pure C++ registry, this would be unnecessary.
185
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));
195
196     xmlrpc_value * retval;
197
198     try {
199         xmlrpc_c::value result;
200
201         try {
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());
208         }
209         if (envP->fault_occurred)
210             retval = NULL;
211         else
212             retval = result.cValue();
213     } catch (...) {
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.");
219         retval = NULL;
220     }
221     return retval;
222 }
223  
224
225
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
237    registry.
238
239    If we had a pure C++ registry, this would be unnecessary.
240
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));
250
251     xmlrpc_value * retval;
252
253     try {
254         value result;
255         
256         try {
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());
263         }
264         if (envP->fault_occurred)
265             retval = NULL;
266         else
267             retval = result.cValue();
268     } catch (...) {
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.");
274         retval = NULL;
275     }
276     return retval;
277 }
278  
279
280
281 void
282 registry::addMethod(string    const name,
283                     methodPtr const methodP) {
284
285     this->methodList.push_back(methodP);
286
287     env_wrap env;
288     
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());
294
295     throwIfError(env);
296 }
297
298
299
300 void
301 registry::setDefaultMethod(defaultMethodPtr const methodP) {
302
303     this->defaultMethodP = methodP;
304
305     env_wrap env;
306     
307     xmlrpc_registry_set_default_method(
308         &env.env_c, this->c_registryP,
309         &c_executeDefaultMethod, (void*) methodP.get());
310
311     throwIfError(env);
312 }
313
314
315
316 void
317 registry::disableIntrospection() {
318
319     xmlrpc_registry_disable_introspection(this->c_registryP);
320 }
321
322
323
324 void
325 registry::processCall(string   const& callXml,
326                       string * const  responseXmlP) const {
327 /*----------------------------------------------------------------------------
328    Process an XML-RPC call whose XML is 'callXml'.
329
330    Return the response XML as *responseXmlP.
331
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 -----------------------------------------------------------------------------*/
336     env_wrap env;
337     xmlrpc_mem_block * output;
338
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.
346
347     output = xmlrpc_registry_process_call(
348         &env.env_c, this->c_registryP, NULL,
349         callXml.c_str(), callXml.length());
350
351     throwIfError(env);
352
353     *responseXmlP = string(XMLRPC_MEMBLOCK_CONTENTS(char, output),
354                            XMLRPC_MEMBLOCK_SIZE(char, output));
355     
356     xmlrpc_mem_block_free(output);
357 }
358
359 xmlrpc_registry *
360 registry::c_registry() const {
361
362     return this->c_registryP;
363 }
364
365 }  // namespace