1 /*
2 * Copyright 1999-2006 University of Chicago
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "globus_soap_message.h"
18 #include "globus_wsrf_resource.h"
19 #include "globus_service_engine.h"
20 #include "globus_operation_provider.h"
21 #include "globus_service_registry.h"
22 #include "globus_wsrf_core_tools.h"
23 #include "version.h"
24 #include "libxml/xpath.h"
25 #include "libxml/xpathInternals.h"
26 #include "libxml/tree.h"
27 #include "libxml/c14n.h"
28 #include "globus_xml_buffer.h"
29 #include <math.h>
30
31 #include "wsrp_QueryResourcePropertiesType.h"
32 #include "wsrp_QueryResourcePropertiesResponseType.h"
33 #include "xpath_Standard.h"
34 #include "xpath_TargetedXPathQueryType.h"
35 #include "xpath_NamespaceMappingType.h"
36
37 #include "wsr_ResourceUnknownFault.h"
38 #include "wsrp_UnknownQueryExpressionDialectFault.h"
39 #include "wsrp_InvalidQueryExpressionFault.h"
40 #include "wsrp_QueryEvaluationErrorFault.h"
41
42 /**
43 * @page wsrp_QueryResourceProperties_provider QueryResourceProperties Provider
44 *
45 * <h2>Provider Usage Overview</h2>
46 * This operation provider implements the QueryResourceProperties portType
47 * defined in
48 * http://docs.oasis-open.org/wsrf/rpw-2 .
49 *
50 * This portType consists of the @a QueryResourceProperties operation and
51 * related faults.
52 *
53 * Currently, this provider supports XPATH Queries using the standard
54 * Dialect attribute "http://www.w3.org/TR/1999/REC-xpath-19991116", and the
55 * MDS-specific Dialect attribute
56 * "http://www.globus.org/namespaces/2006/07/TargetedXPath"
57 *
58 * The WSRF service engine will automatically register this provider to handle
59 * the QueryResourceProperties operation for services which use the port type.
60 */
61
62 /* Prototypes */
63 static
64 globus_result_t
65 wsrp_QueryResourceProperties_provider(
66 globus_service_engine_t engine,
67 globus_soap_message_handle_t message,
68 globus_service_descriptor_t * service,
69 wsrp_QueryResourcePropertiesType * QueryResourceProperties,
70 wsrp_QueryResourcePropertiesResponseType *
71 QueryResourcePropertiesResponse,
72 xsd_any * fault);
73
74 static
75 int
76 wsrp_QueryResourceProperties_activate(void);
77
78 static
79 int
80 wsrp_QueryResourceProperties_deactivate(void);
81
82 static
83 globus_result_t
84 wsrp_l_c14n_node(
85 xmlDocPtr cur_doc,
86 xmlNodePtr cur_node,
87 xmlChar ** data);
88
89 /* Local Variables */
90 static xsd_QName wsrp_QueryResourceProperties_qname =
91 {
92 "http://docs.oasis-open.org/wsrf/rpw-2/providers",
93 "QueryResourceProperties"
94 };
95
96 static
97 globus_operation_provider_descriptor_t
98 wsrp_QueryResourceProperties_descriptor =
99 {
100 &wsrp_QueryResourceProperties_qname,
101 "QueryResourceProperties",
102 (void *)wsrp_QueryResourceProperties_provider,
103 NULL
104 };
105
106 GlobusExtensionDefineModule(globus_wsrp_QueryResourceProperties_provider) =
107 {
108 "globus_wsrp_QueryResourceProperties_provider",
109 wsrp_QueryResourceProperties_activate,
110 wsrp_QueryResourceProperties_deactivate,
111 NULL,
112 NULL,
113 &local_version
114 };
115
116 /* Implementation */
117
118 #define RP_DOC_NS "http://www.globus.org/namespaces/2006/04/QueryResourceProperties"
119 #define RP_DOC "Document"
120
121 static
122 globus_result_t
123 wsrp_QueryResourceProperties_provider(
124 globus_service_engine_t engine,
125 globus_soap_message_handle_t message,
126 globus_service_descriptor_t * service,
127 wsrp_QueryResourcePropertiesType * QueryResourceProperties,
128 wsrp_QueryResourcePropertiesResponseType *
129 QueryResourcePropertiesResponse,
130 xsd_any * fault)
131 130 {
132 globus_result_t result;
133 globus_resource_t resource;
134 130 xsd_QName_array * property_names = NULL;
135 130 globus_soap_message_handle_t dom_handle = NULL;
136 130 xmlDocPtr dom = NULL;
137 xsd_anyType rp_doc_element;
138 130 xsd_any_array * rp_array = NULL;
139 130 xsd_any * tmp = NULL;
140 130 xsd_QName rp_doc_element_qname = { RP_DOC_NS, RP_DOC};
141 int i;
142 xmlXPathContextPtr xpath_context;
143 xmlXPathObjectPtr xpath_result;
144 xmlXPathCompExprPtr xpath_expression;
145 xpath_TargetedXPathQueryType * serialized_expression;
146
147 130 result = globus_wsrf_core_get_resource(
148 message,
149 service,
150 &resource);
151
152 130 if (result != GLOBUS_SUCCESS || resource == NULL)
153 {
154 0 result = globus_wsrf_core_create_fault(
155 fault,
156 &wsr_ResourceUnknownFault_qname);
157
158 0 goto out;
159 }
160 130 if (QueryResourceProperties->QueryExpression._Dialect == NULL ||
161 ((strcmp(*QueryResourceProperties->QueryExpression._Dialect,
162 "http://www.w3.org/TR/1999/REC-xpath-19991116") != 0) &&
163 strcmp(*QueryResourceProperties->QueryExpression._Dialect,
164 "http://www.globus.org/namespaces/2006/07/TargetedXPath") != 0))
165 {
166 /* Unknown/unsupported dialect */
167 0 result = globus_wsrf_core_create_fault(
168 fault,
169 &wsrp_UnknownQueryExpressionDialectFault_qname);
170
171 0 goto finish_out;
172 }
173 130 result = globus_resource_enumerate_properties(
174 resource,
175 &property_names);
176 130 if (result != GLOBUS_SUCCESS)
177 {
178 0 goto finish_out;
179 }
180 130 if (QueryResourceProperties->QueryExpression.any->any_info !=
181 &xpath_TargetedXPathQueryType_info &&
182 QueryResourceProperties->QueryExpression.any->any_info !=
183 &xpath_Standard_contents_info)
184 {
185 0 result = globus_wsrf_core_create_fault(
186 fault,
187 &wsrp_InvalidQueryExpressionFault_qname);
188 0 goto free_property_qnames;
189 }
190 /* Create a document containing all of the resource properties */
191 130 serialized_expression = QueryResourceProperties->QueryExpression.any->value;
192 130 result = xsd_anyType_init_contents(&rp_doc_element);
193 130 if (result != GLOBUS_SUCCESS)
194 {
195 0 goto free_property_qnames;
196 }
197 130 rp_doc_element.any_info = &xsd_any_array_info;
198
199 130 result = xsd_any_array_init(&rp_array);
200 130 if (result != GLOBUS_SUCCESS)
201 {
202 0 goto free_rp_doc_element;
203 }
204 130 rp_doc_element.value = rp_array;
205
206 278 for (i = 0; i < property_names->length; i++)
207 {
208 xsd_any * tmp;
209 void * prop_value;
210 globus_xsd_type_info_t prop_type_info;
211
212 148 if (serialized_expression->resourcePropertyName != NULL &&
213 ! xsd_QName_keyeq(serialized_expression->resourcePropertyName,
214 &property_names->elements[i]))
215 {
216 6 continue;
217 }
218
219 142 result = globus_resource_get_property(
220 resource,
221 &property_names->elements[i],
222 &prop_value,
223 &prop_type_info);
224 142 if (result != GLOBUS_SUCCESS)
225 {
226 0 goto free_rp_doc_element;
227 }
228 142 tmp = xsd_any_array_push(rp_array);
229 142 if (tmp == NULL)
230 {
231 0 goto free_rp_doc_element;
232 }
233 142 result = xsd_QName_copy(&tmp->element, &property_names->elements[i]);
234 142 if (result != GLOBUS_SUCCESS)
235 {
236 0 goto free_rp_doc_element;
237 }
238 142 tmp->any_info = prop_type_info;
239
240 142 if (prop_value != NULL)
241 {
242 142 result = prop_type_info->copy(&tmp->value, prop_value);
243 142 if (result != GLOBUS_SUCCESS)
244 {
245 0 goto free_rp_doc_element;
246 }
247 }
248 }
249
250 /* Serialize the document to a DOM */
251 130 result = globus_soap_message_handle_init_to_dom(&dom_handle, &dom);
252 130 if (result != GLOBUS_SUCCESS)
253 {
254 0 goto free_rp_doc_element;
255 }
256 130 result = xsd_anyType_serialize(
257 &rp_doc_element_qname,
258 &rp_doc_element,
259 dom_handle,
260 0);
261 130 if (result != GLOBUS_SUCCESS)
262 {
263 0 goto free_dom_handle;
264 }
265 130 globus_soap_message_handle_destroy(dom_handle);
266 130 dom_handle = NULL;
267
268 /* Perform XPATH query on the DOM */
269 130 xpath_context = xmlXPathNewContext(dom);
270 574 for (i = 0; i < serialized_expression->namespaceMappings.length; i++)
271 {
272 444 xmlXPathRegisterNs(xpath_context,
273 (xmlChar *) serialized_expression->namespaceMappings.elements[i].mappedName,
274 (xmlChar *) serialized_expression->namespaceMappings.elements[i].Namespace);
275 }
276
277 130 xpath_expression = xmlXPathCompile(
278 (xmlChar *) serialized_expression->queryString);
279 130 if (xpath_expression == NULL)
280 {
281 0 result = globus_wsrf_core_create_fault(
282 fault,
283 &wsrp_InvalidQueryExpressionFault_qname);
284 0 goto free_xpath_context;
285 }
286 130 xpath_result = xmlXPathCompiledEval(xpath_expression, xpath_context);
287 130 if (xpath_result == NULL ||
288 (xpath_result->type == XPATH_NODESET &&
289 (xpath_result->nodesetval == NULL ||
290 xpath_result->nodesetval->nodeNr == 0)))
291 {
292 12 result = globus_wsrf_core_create_fault(
293 fault,
294 &wsrp_QueryEvaluationErrorFault_qname);
295 12 goto free_xpath_result;
296 }
297 /* Transform XPATH result into a QueryResourcePropertiesResponseType */
298 118 switch (xpath_result->type)
299 {
300 case XPATH_UNDEFINED:
301 0 break;
302 case XPATH_NODESET:
303 144 for (i = 0; i < xpath_result->nodesetval->nodeNr; i++)
304 {
305 78 tmp = xsd_any_array_push(&QueryResourcePropertiesResponse->any);
306
307 /* If the entire doc is returned, xmlNodeDump will not work
308 * properly as the type of the node is not castable to
309 * xmlNodePtr
310 */
311 78 if (dom == (xmlDocPtr) xpath_result->nodesetval->nodeTab[i])
312 {
313 0 globus_xml_buffer_array * gbuf_array = NULL;
314 0 globus_xml_buffer * gbuf = NULL;
315 0 xmlNodePtr tnode = dom->children->children;
316
317 0 tmp->any_info = &globus_xml_buffer_array_info;
318 0 globus_xml_buffer_array_init(&gbuf_array);
319 0 tmp->value = gbuf_array;
320
321 0 while (tnode != NULL)
322 {
323 xmlBufferPtr buf;
324 0 buf = xmlBufferCreate();
325
326 0 xmlNodeDump(buf, dom, tnode, 0, 0);
327 0 gbuf = globus_xml_buffer_array_push(gbuf_array);
328 0 gbuf->buffer = malloc(buf->use);
329 0 gbuf->length = buf->use;
330 0 memcpy(gbuf->buffer, buf->content, buf->use);
331
332 0 tnode = tnode->next;
333 0 xmlBufferFree(buf);
334 }
335 }
336 78 else if (xpath_result->nodesetval->nodeTab[i]->type == XML_ATTRIBUTE_NODE)
337 {
338 36 globus_xml_buffer * gbuf = NULL;
339 xmlBufferPtr buf;
340 36 buf = xmlBufferCreate();
341
342 36 globus_xml_buffer_init(&gbuf);
343 36 tmp->any_info = &globus_xml_buffer_info;
344 36 tmp->element = NULL;
345 36 tmp->value = gbuf;
346 36 xmlNodeDump(buf, dom, xpath_result->nodesetval->nodeTab[i]->children, 0, 0);
347 36 gbuf->buffer = malloc(buf->use+1);
348 36 gbuf->length = buf->use+1;
349 36 gbuf->buffer[0] = ' ';
350 36 memcpy(gbuf->buffer+1, buf->content, buf->use);
351 36 xmlBufferFree(buf);
352 }
353 else
354 {
355 42 globus_xml_buffer * gbuf = NULL;
356
357 42 globus_xml_buffer_init(&gbuf);
358 42 tmp->any_info = &globus_xml_buffer_info;
359 42 tmp->element = NULL;
360 42 tmp->value = gbuf;
361 42 result = wsrp_l_c14n_node(dom,
362 xpath_result->nodesetval->nodeTab[i],
363 (xmlChar **) &gbuf->buffer);
364 42 gbuf->length = strlen(gbuf->buffer);
365 }
366
367 }
368
369 66 break;
370
371 case XPATH_BOOLEAN:
372 {
373 28 xsd_boolean * b = NULL;
374 28 tmp = xsd_any_array_push(&QueryResourcePropertiesResponse->any);
375 28 tmp->any_info = &xsd_boolean_info;
376 28 xsd_boolean_init(&b);
377 28 *b = xpath_result->boolval;
378 28 tmp->value = b;
379 }
380 28 break;
381
382 case XPATH_NUMBER:
383 24 if (floor(xpath_result->floatval) == ceil(xpath_result->floatval))
384 {
385 24 xsd_long * l = NULL;
386
387 24 tmp = xsd_any_array_push(&QueryResourcePropertiesResponse->any);
388 24 tmp->any_info = &xsd_long_info;
389 24 xsd_long_init(&l);
390 24 *l = (long) xpath_result->floatval;
391 24 tmp->value = l;
392 }
393 else
394 {
395 0 xsd_double * d = NULL;
396
397 0 tmp = xsd_any_array_push(&QueryResourcePropertiesResponse->any);
398 0 tmp->any_info = &xsd_double_info;
399 0 xsd_double_init(&d);
400 0 *d = xpath_result->floatval;
401 0 tmp->value = d;
402 }
403 24 break;
404 case XPATH_STRING:
405 {
406 0 xsd_string * s = NULL;
407
408 0 tmp = xsd_any_array_push(&QueryResourcePropertiesResponse->any);
409 0 tmp->any_info = &xsd_string_info;
410 0 xsd_string_init_cstr(&s, (xsd_string) xpath_result->stringval);
411 0 tmp->value = s;
412 }
413 break;
414 case XPATH_POINT:
415 case XPATH_RANGE:
416 case XPATH_LOCATIONSET:
417 case XPATH_USERS:
418 case XPATH_XSLT_TREE:
419 break;
420 }
421 130 free_xpath_result:
422 130 if (xpath_result != NULL)
423 {
424 130 xmlXPathFreeObject(xpath_result);
425 }
426 130 xmlXPathFreeCompExpr(xpath_expression);
427 130 free_xpath_context:
428 130 xmlXPathFreeContext(xpath_context);
429 130 free_dom_handle:
430 130 if (dom_handle != NULL)
431 {
432 0 globus_soap_message_handle_destroy(dom_handle);
433 0 dom_handle = NULL;
434 }
435 130 free_rp_doc_element:
436 130 xsd_anyType_destroy_contents(&rp_doc_element);
437 130 free_property_qnames:
438 130 xsd_QName_array_destroy(property_names);
439 130 finish_out:
440 130 globus_resource_finish(resource);
441 130 out:
442 130 return result;
443 }
444 /* wsrp_QueryResourceProperties_provider() */
445
446 static
447 int
448 wsrp_QueryResourceProperties_activate(void)
449 311 {
450 311 int res = 0;
451 GlobusFuncName(wsrp_QueryResourceProperties_activate);
452
453
454 311 res = globus_extension_registry_add(
455 GLOBUS_OPERATION_PROVIDER_REGISTRY,
456 &wsrp_QueryResourceProperties_qname,
457 GlobusExtensionMyModule(globus_wsrp_QueryResourceProperties_provider),
458 &wsrp_QueryResourceProperties_descriptor);
459
460 311 return res;
461 }
462 /* wsrp_QueryResourceProperties_activate(void) */
463
464 static
465 int
466 wsrp_QueryResourceProperties_deactivate(void)
467 42 {
468 GlobusFuncName(wsrp_QueryResourceProperties_deactivate);
469
470 42 globus_extension_registry_remove(
471 GLOBUS_OPERATION_PROVIDER_REGISTRY,
472 &wsrp_QueryResourceProperties_qname);
473
474 42 return 0;
475 }
476 /* wsrp_QueryResourceProperties_deactivate() */
477
478 static
479 globus_result_t
480 wsrp_l_c14n_node(
481 xmlDocPtr cur_doc,
482 xmlNodePtr cur_node,
483 xmlChar ** data)
484 42 {
485 xmlDocPtr doc;
486 xmlNodePtr node;
487 xmlNsPtr * ns_list;
488 xmlChar ** ns_prefixes;
489 int i;
490 int j;
491
492 /* Canonicalize the XML when dumping so that the data can be used
493 * in other XML documents
494 */
495 42 node = xmlDocCopyNode(cur_node, cur_doc, 1);
496
497 42 doc = xmlNewDoc(BAD_CAST "1.0");
498 42 xmlDocSetRootElement(doc, node);
499
500 42 ns_list = xmlGetNsList(cur_doc, cur_node);
501
502 42 if (ns_list != NULL)
503 {
504 42 for (i = 0; ns_list[i] != NULL; i++)
505 {
506 }
507
508 42 ns_prefixes = malloc((i+1) * sizeof(xmlChar*));
509
510 210 for (i = 0, j = 0; ns_list[i] != NULL; i++)
511 {
512 168 if (ns_list[i]->prefix != NULL)
513 {
514 168 ns_prefixes[j++] = xmlStrdup(ns_list[i]->prefix);
515 }
516 168 xmlNewNs(node, ns_list[i]->href, ns_list[i]->prefix);
517 }
518 42 ns_prefixes[j++] = NULL;
519
520 42 xmlFree(ns_list);
521 }
522
523 42 if (xmlC14NDocDumpMemory(doc, NULL, 1, ns_prefixes, 0, data) == -1)
524 {
525 0 xmlFreeDoc(doc);
526 0 xmlFree(ns_prefixes);
527 0 return GlobusSoapMessageErrorOutOfMemory;
528 }
529 210 for (i = 0; ns_prefixes[i] != NULL; i++)
530 {
531 168 xmlFree(ns_prefixes[i]);
532 }
533 42 xmlFree(ns_prefixes);
534 42 xmlFreeDoc(doc);
535 42 return GLOBUS_SUCCESS;
536 }