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_i_wsrf_resource.h"
18 #include "xsd_any.h"
19
20 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
21 /**
22 * @file globus_wsrf_resource_property.c
23 * Resource Property Functions
24 * @author $author$
25 * @date $date$
26 * @version $version$
27 */
28 #endif /* GLOBUS_DONT_DOCUMENT_INTERNAL */
29
30 static
31 xsd_QName globus_l_resource_properties_any_qname = {
32 "any",
33 "any"
34 };
35
36 const xsd_QName * globus_resource_properties_any_qname =
37 &globus_l_resource_properties_any_qname;
38 static
39 globus_result_t
40 globus_l_resource_create_property(
41 globus_resource_t resource,
42 const xsd_QName * qname,
43 const globus_xsd_type_info_t type_info,
44 void * property,
45 globus_resource_property_get_callback_t
46 get_callback,
47 globus_resource_property_set_callback_t
48 set_callback,
49 void * callback_arg);
50
51 static
52 globus_result_t
53 globus_l_resource_get_any_property(
54 globus_resource_t resource,
55 const xsd_QName * qname,
56 void ** property,
57 globus_xsd_type_info_t * info);
58
59 static
60 globus_result_t
61 globus_l_resource_set_any_property(
62 globus_resource_t resource,
63 const xsd_QName * qname,
64 void * property);
65
66 static
67 void
68 globus_l_resource_property_changed(
69 globus_resource_t resource,
70 globus_bool_t new_property,
71 const xsd_QName * qname,
72 void * value,
73 const globus_xsd_type_info_t type_info);
74
75 static
76 int
77 globus_l_resource_callback_equal(
78 void * datum,
79 void * callback);
80
81 /**
82 * Get the value of the named Resource Property.
83 * @ingroup resource_property
84 *
85 * @param resource
86 * Resource containing the property.
87 * @param qname
88 * Name of the Resource Property element.
89 * @param property
90 * Pointer to return the value of the property.
91 * @param type_info
92 * Pointer to return the type info for this property. This may be NULL.
93 *
94 * @retval GLOBUS_SUCCESS
95 * Resource Property found and its value returned in @a property.
96 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
97 * One of the parameters to this function was NULL.
98 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
99 * The resource does not contain a property with the specified name.
100 */
101 globus_result_t
102 globus_resource_get_property(
103 globus_resource_t resource,
104 const xsd_QName * qname,
105 void ** property,
106 globus_xsd_type_info_t * type_info)
107 2492372 {
108 2492372 globus_result_t result = GLOBUS_SUCCESS;
109 2492372 globus_resource_property_t * prop = NULL;
110 GlobusFuncName(globus_resource_get_property);
111
112 2492372 if (resource == NULL || qname == NULL || property == NULL)
113 {
114 9 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
115 }
116
117 2492363 *property = NULL;
118
119 2492363 prop = globus_hashtable_lookup(
120 &resource->resource_properties,
121 (void *) qname);
122
123 2492363 if (prop != NULL)
124 {
125 2491970 if (prop->get_callback != NULL)
126 {
127 319 prop->get_callback(prop->callback_arg, qname, property);
128
129 319 if (prop->property != NULL)
130 {
131 99 prop->type_info->destroy(prop->property);
132 }
133 319 prop->property = *property;
134 }
135 else
136 {
137 2491651 *property = prop->property;
138 }
139 2491970 if (type_info != NULL)
140 {
141 2491814 (*type_info) = prop->type_info;
142 }
143 }
144 else
145 {
146 393 result = globus_l_resource_get_any_property(
147 resource,
148 qname,
149 property,
150 type_info);
151
152 if (result != GLOBUS_SUCCESS)
153 {
154 393 goto out;
155 }
156 }
157
158 2492363 out:
159 2492363 return result;
160 }
161 /* globus_resource_get_property() */
162
163 /**
164 * Set the value of the named Resource Property.
165 * @ingroup resource_property
166 *
167 * Changes the current value of the named Resource Property to be that of
168 * the @a property parameter. If the Resource Property already had a value
169 * set by a previous call to this function or
170 * #globus_resource_create_property(), the old value will be destroyed, using
171 * the functions included in the type info associated with the property.
172 *
173 * @param resource
174 * Resource containing the property.
175 * @param qname
176 * Name of the Resource Property element.
177 * @param property
178 * New value of the property.
179 *
180 * @retval GLOBUS_SUCCESS
181 * Resource Property found and its value returned in @a property.
182 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
183 * One of the parameters to this function was NULL.
184 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
185 * The resource does not contain a property with the specified name.
186 */
187 globus_result_t
188 globus_resource_set_property(
189 globus_resource_t resource,
190 const xsd_QName * qname,
191 void * property)
192 1087 {
193 1087 globus_result_t result = GLOBUS_SUCCESS;
194 1087 globus_resource_property_t * prop = NULL;
195 1087 globus_bool_t allowed = GLOBUS_TRUE;
196 GlobusFuncName(globus_resource_set_property);
197
198 1087 if (resource == NULL || qname == NULL)
199 {
200 6 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
201 }
202
203 1081 prop = globus_hashtable_lookup(
204 &resource->resource_properties,
205 (void*) qname);
206
207 1081 if (prop != NULL)
208 {
209 1042 if (prop->set_callback != NULL)
210 {
211 0 allowed = prop->set_callback(prop->callback_arg, qname, property);
212 }
213
214 1042 if (! allowed)
215 {
216 0 result = GLOBUS_RESOURCE_ERROR_CHANGE_DENIED(qname);
217
218 0 goto out;
219 }
220
221 1042 if (prop->property != NULL && prop->type_info->destroy != NULL)
222 {
223 786 prop->type_info->destroy(prop->property);
224 }
225
226 1042 prop->property = property;
227 }
228 else
229 {
230 39 result = globus_l_resource_set_any_property(
231 resource,
232 qname,
233 property);
234 }
235
236 1081 if (result == GLOBUS_SUCCESS)
237 {
238 /* prop may be null if set_any_property is called with a NULL
239 * property value
240 */
241 1078 globus_l_resource_property_changed(
242 resource,
243 GLOBUS_FALSE,
244 qname,
245 property,
246 prop ? prop->type_info : NULL);
247 }
248 1081 out:
249 1081 return result;
250 }
251 /* globus_resource_set_property() */
252
253 /**
254 * Create a new Resource Property.
255 * @ingroup resource_property
256 *
257 * Modifies the resource to contain a new Resource Property with the given
258 * element name and type information. The initial value of the property will
259 * be set to the @a property parameter's value.
260 *
261 * @param resource
262 * Resource with which to associated the new resource property.
263 * @param qname
264 * Name of the resource property element.
265 * @param type_info
266 * XSD type mapping for this resource property type. This mapping
267 * describes how to access the value contained in the @a property
268 * parameter.
269 * @param property
270 * Initial value of the property.
271 *
272 * @retval GLOBUS_SUCCESS
273 * Property successfully created.
274 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
275 * One of the parameters to this function was NULL.
276 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_DUPLICATE_PROPERTY
277 * A Resource Property with the given QName already exists in this
278 * resource.
279 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_OUT_OF_MEMORY
280 * Not enough memory to allocate the new Resource Property.
281 */
282 globus_result_t
283 globus_resource_create_property(
284 globus_resource_t resource,
285 const xsd_QName * qname,
286 const globus_xsd_type_info_t type_info,
287 void * property)
288 2374 {
289 2374 return globus_l_resource_create_property(
290 resource,
291 qname,
292 type_info,
293 property,
294 NULL,
295 NULL,
296 NULL);
297 }
298 /* globus_resource_create_property() */
299
300 /**
301 * Create a new dynamic-valued Resource Property.
302 * @ingroup resource_property
303 *
304 * Modifies the resource to contain a new Resource Property with the given
305 * element name and type information. The value of the property is determined
306 * by calling the callback function. Subsequent calls to
307 * globus_resource_get_property() will delete the previous value generated by
308 * the callback.
309 *
310 * @param resource
311 * Resource with which to associated the new resource property.
312 * @param qname
313 * Name of the resource property element.
314 * @param type_info
315 * XSD type mapping for this resource property type. This mapping
316 * describes how to access the value contained in the @a property
317 * parameter.
318 * @param get_callback
319 * Callback to request the current value of a dynamic-valued Resource
320 * Property.
321 * @param set_callback
322 * Callback to propose a change to the current value of a dynamic-valued
323 * Resource Property.
324 * @param callback_arg
325 * User-specific callback argument passed to the @a get_callback and
326 * @a set_callback functions.
327 *
328 * @retval GLOBUS_SUCCESS
329 * Property successfully created.
330 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
331 * One of the parameters to this function was NULL.
332 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_DUPLICATE_PROPERTY
333 * A Resource Property with the given QName already exists in this
334 * resource.
335 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_OUT_OF_MEMORY
336 * Not enough memory to allocate the new Resource Property.
337 */
338 globus_result_t
339 globus_resource_create_property_callback(
340 globus_resource_t resource,
341 const xsd_QName * qname,
342 const globus_xsd_type_info_t type_info,
343 globus_resource_property_get_callback_t
344 get_callback,
345 globus_resource_property_set_callback_t
346 set_callback,
347 void * callback_arg)
348 912 {
349 GlobusFuncName(globus_resource_create_property_callback);
350
351 912 if (get_callback == NULL || set_callback == NULL)
352 {
353 6 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
354 }
355
356 906 return globus_l_resource_create_property(
357 resource,
358 qname,
359 type_info,
360 NULL,
361 get_callback,
362 set_callback,
363 callback_arg);
364 }
365 /* globus_resource_create_property_callback() */
366
367 /**
368 * Signal the resource that the value of a resource property has changed.
369 * @ingroup resource_property
370 *
371 * Causes all resource property change callbacks to be called with the current
372 * value of this resource property. This function does not need to be called
373 * for resource properties whose values were changed due to calling
374 * globus_resource_set_property(), only for dynamic valued resource properties.
375 *
376 * @param resource
377 * Resource with which to associated the new resource property.
378 * @param qname
379 * QName of the resource property which has a changed value.
380 */
381 globus_result_t
382 globus_resource_property_changed(
383 globus_resource_t resource,
384 const xsd_QName * qname)
385 304 {
386 globus_xsd_type_info_t type_info;
387 void * property;
388 304 globus_result_t result = GLOBUS_SUCCESS;
389 GlobusFuncName(globus_resource_property_changed);
390
391 304 if (resource == NULL || qname == NULL)
392 {
393 0 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
394 }
395
396 304 if (resource->property_changed_callbacks == NULL)
397 {
398 0 goto out;
399 }
400
401 304 result = globus_resource_get_property(
402 resource,
403 qname,
404 &property,
405 &type_info);
406
407 304 if (result != GLOBUS_SUCCESS)
408 {
409 0 goto out;
410 }
411
412 304 globus_l_resource_property_changed(
413 resource,
414 GLOBUS_FALSE,
415 qname,
416 property,
417 type_info);
418
419 304 out:
420 304 return result;
421 }
422 /* globus_resource_property_changed() */
423
424 /**
425 * Add a new function to be called when a resource property value changes.
426 * @ingroup resource_property
427 *
428 * Adds a new function to the list of those to be called whenever a resource
429 * property value changes. This function will be called with the resource
430 * property name, new value, and type_info. If the callback wishes to access
431 * the value after it returns, it must copy the value using the type info.
432 *
433 * @param resource
434 * Resource with which to associated the new resource property.
435 * @param callback
436 * Pointer to the function to call when the property value changes.
437 * @param callback_arg
438 * Callback-specific data.
439 */
440 globus_result_t
441 globus_resource_add_property_changed_callback(
442 globus_resource_t resource,
443 globus_resource_property_changed_callback_t
444 callback,
445 void * callback_arg)
446 295 {
447 295 globus_result_t result = GLOBUS_SUCCESS;
448 int rc;
449 globus_list_t * tmp;
450 globus_i_resource_property_changed_callback_t *
451 callback_info;
452 GlobusFuncName(globus_resource_add_property_changed_callback);
453
454 295 if (resource == NULL || callback == NULL)
455 {
456 0 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
457 }
458
459 295 tmp = globus_list_search_pred(
460 resource->property_changed_callbacks,
461 globus_l_resource_callback_equal,
462 callback);
463 295 if (tmp != NULL)
464 {
465 0 goto out;
466 }
467 295 callback_info = globus_libc_malloc(
468 sizeof(globus_i_resource_property_changed_callback_t));
469 295 if (callback_info == NULL)
470 {
471 0 result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
472
473 0 goto out;
474 }
475
476 295 callback_info->callback = callback;
477 295 callback_info->callback_arg = callback_arg;
478
479 295 rc = globus_list_insert(
480 &resource->property_changed_callbacks,
481 callback_info);
482
483 295 if (rc != GLOBUS_SUCCESS)
484 {
485 0 globus_libc_free(callback_info);
486
487 0 result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
488
489 0 goto out;
490 }
491
492 295 out:
493 295 return result;
494 }
495 /* globus_resource_add_property_changed_callback() */
496
497 globus_result_t
498 globus_resource_remove_property_changed_callback(
499 globus_resource_t resource,
500 globus_resource_property_changed_callback_t
501 callback,
502 void * callback_arg)
503 0 {
504 0 globus_result_t result = GLOBUS_SUCCESS;
505 globus_list_t * tmp;
506 globus_i_resource_property_changed_callback_t *
507 callback_info;
508 GlobusFuncName(globus_resource_remove_property_changed_callback);
509
510 0 if (resource == NULL || callback == NULL)
511 {
512 0 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
513 }
514 0 tmp = globus_list_search_pred(
515 resource->property_changed_callbacks,
516 globus_l_resource_callback_equal,
517 callback);
518
519 0 if (tmp != GLOBUS_NULL)
520 {
521 0 callback_info = globus_list_remove(
522 &resource->property_changed_callbacks,
523 tmp);
524
525 0 if (callback_info)
526 {
527 0 globus_libc_free(callback_info);
528 }
529 }
530
531 0 return result;
532 }
533 /* globus_resource_remove_property_changed_callback() */
534
535 /**
536 * Remove the named resource property from a resource.
537 * @ingroup resource_property
538 *
539 * The property's current value and type info is returned in the @a property
540 * and @a type_info parameters respectively.
541 *
542 * @param resource
543 * Resource containing the property.
544 * @param qname
545 * Element name of the resource property.
546 * @param property
547 * Pointer to be set to point to the value of the resource property.
548 * @param type_info
549 * Pointer to be set to type information about the property value.
550 *
551 * @retval GLOBUS_SUCCESS
552 * Resource Property successfully deleted.
553 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
554 * One of the parameters to this function was NULL.
555 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
556 * The resource does not contain a property with the specified name.
557 */
558 globus_result_t
559 globus_resource_delete_property(
560 globus_resource_t resource,
561 const xsd_QName * qname,
562 void ** property,
563 globus_xsd_type_info_t * type_info)
564 18 {
565 18 globus_resource_property_t * prop = NULL;
566 18 globus_result_t result = GLOBUS_SUCCESS;
567 GlobusFuncName(globus_resource_delete_property);
568
569 18 if (resource == NULL || qname == NULL || property == NULL ||
570 type_info == NULL)
571 {
572 12 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
573 }
574
575 6 if (resource->resource_properties != NULL)
576 {
577 6 prop = globus_hashtable_remove(
578 &resource->resource_properties,
579 (void*) qname);
580 }
581
582 6 if (prop == NULL)
583 {
584 3 result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
585
586 3 goto out;
587 }
588
589 3 *property = prop->property;
590 3 *type_info = prop->type_info;
591
592 3 globus_free(prop->name.Namespace);
593 3 globus_free(prop->name.local);
594 3 globus_free(prop);
595 6 out:
596
597 6 return result;
598 }
599 /* globus_resource_delete_property() */
600
601 /**
602 * Destroy a named resource property.
603 * @ingroup resource_property
604 *
605 * The current value of the property is destroyed. Subsequent attempts to
606 * access the property will fail.
607 *
608 * and @a type_info parameters respectively.
609 *
610 * @param resource
611 * Resource containing the property.
612 * @param qname
613 * Element name of the resource property.
614 * @retval GLOBUS_SUCCESS
615 * The property was successfully destroyed
616 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
617 * One of the parameters to this function was NULL.
618 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
619 * The resource does not contain a property with the specified name.
620 */
621 globus_result_t
622 globus_resource_destroy_property(
623 globus_resource_t resource,
624 const xsd_QName * qname)
625 18 {
626 18 globus_resource_property_t * prop = NULL;
627 18 globus_result_t result = GLOBUS_SUCCESS;
628 GlobusFuncName(globus_resource_destroy_property);
629
630 18 if (resource == NULL || qname == NULL)
631 {
632 6 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
633 }
634
635 12 if (resource->resource_properties != NULL)
636 {
637 12 prop = globus_hashtable_remove(
638 &resource->resource_properties,
639 (void *) qname);
640 }
641
642 12 if (prop == NULL)
643 {
644 3 result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
645 3 goto out;
646 }
647
648 9 if (prop->property != NULL)
649 {
650 3 prop->type_info->destroy(prop->property);
651 }
652
653 9 free(prop->name.Namespace);
654 9 free(prop->name.local);
655 9 free(prop);
656
657 12 out:
658 12 return result;
659 }
660 /* globus_resource_destroy_property() */
661
662 globus_result_t
663 globus_resource_enumerate_properties(
664 const globus_resource_t resource,
665 xsd_QName_array ** property_names)
666 424 {
667 globus_result_t result;
668 globus_resource_property_t * tmp;
669 xsd_QName * name;
670
671 424 if (property_names == NULL)
672 {
673 0 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
674
675 goto out;
676 }
677
678 424 if (resource == NULL)
679 {
680 0 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
681
682 goto nullify_property_names_out;
683 }
684
685 424 result = xsd_QName_array_init(property_names);
686
687 424 if (result != GLOBUS_SUCCESS)
688 {
689 0 result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
690
691 0 goto nullify_property_names_out;
692 }
693
694 424 tmp = globus_hashtable_first(&resource->resource_properties);
695
696 2752 while (tmp != NULL)
697 {
698 1904 name = xsd_QName_array_push(*property_names);
699
700 1904 if (name == NULL)
701 {
702 0 result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
703
704 0 goto free_array_out;
705 }
706
707 1904 result = xsd_QName_copy_contents(name, &tmp->name);
708
709 1904 if (result != GLOBUS_SUCCESS)
710 {
711 0 result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
712
713 0 goto free_array_out;
714 }
715
716 1904 tmp = globus_hashtable_next(&resource->resource_properties);
717 }
718
719 424 if (result != GLOBUS_SUCCESS)
720 {
721 0 free_array_out:
722 0 xsd_QName_array_destroy(*property_names);
723 0 nullify_property_names_out:
724 0 *property_names = NULL;
725 }
726 424 out:
727 424 return result;
728 }
729 /* globus_resource_enumerate_properties() */
730
731 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
732 /**
733 * Internal implementation of Resource Property creation.
734 *
735 * Modifies the resource to contain a new Resource Property with the given
736 * element name and type information. The initial value of the property will
737 * be set to the @a property parameter's value.
738 *
739 * @param resource
740 * Resource with which to associated the new resource property.
741 * @param qname
742 * Name of the resource property element.
743 * @param type_info
744 * XSD type mapping for this resource property type. This mapping
745 * describes how to access the value contained in the @a property
746 * parameter.
747 * @param property
748 * Initial value of the property.
749 * @param callback
750 * Callback when creating a dynamic-valued Resource Property.
751 * @param callback_arg
752 * User-specific callback argument for dynamic Resource Property
753 * value callbacks.
754 *
755 * @retval GLOBUS_SUCCESS
756 * Property successfully created.
757 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
758 * One of the parameters to this function was NULL.
759 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_DUPLICATE_PROPERTY
760 * A Resource Property with the given QName already exists in this
761 * resource.
762 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_OUT_OF_MEMORY
763 * Not enough memory to allocate the new Resource Property.
764 */
765 static
766 globus_result_t
767 globus_l_resource_create_property(
768 globus_resource_t resource,
769 const xsd_QName * qname,
770 const globus_xsd_type_info_t type_info,
771 void * property,
772 globus_resource_property_get_callback_t
773 get_callback,
774 globus_resource_property_set_callback_t
775 set_callback,
776 void * callback_arg)
777 3280 {
778 globus_resource_property_t * prop;
779 globus_result_t result;
780 int rc;
781 GlobusFuncName(globus_l_resource_create_property);
782
783 3280 if (resource == NULL || qname == NULL || type_info == NULL)
784 {
785 18 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
786 }
787
788 /* If the globus_resource_properties_any_qname is used for the property
789 * name, it must be either an any or any_array and must not have a callback
790 */
791 3262 if (xsd_QName_keyeq(
792 (void *) qname,
793 (void *) globus_resource_properties_any_qname) &&
794 ((type_info != &xsd_any_info && type_info != &xsd_any_array_info)
795 || (get_callback != NULL)))
796 {
797 0 result = GLOBUS_RESOURCE_ERROR_INVALID_ANY();
798
799 0 goto error;
800 }
801
802 3262 prop = globus_hashtable_lookup(
803 &resource->resource_properties,
804 (void *) qname);
805
806 3262 if (prop != NULL)
807 {
808 6 result = GLOBUS_RESOURCE_ERROR_DUPLICATE_PROPERTY(qname);
809
810 6 goto error;
811 }
812 3256 prop = malloc(sizeof(struct globus_resource_property_s));
813
814 3256 if (prop == NULL)
815 {
816 0 result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
817
818 0 goto error;
819 }
820
821 3256 result = xsd_QName_copy_contents(&prop->name, qname);
822 3256 if(result != GLOBUS_SUCCESS)
823 {
824 0 goto free_prop_error;
825 }
826 3256 prop->type_info = type_info;
827 3256 prop->property = property;
828 3256 prop->get_callback = get_callback;
829 3256 prop->set_callback = set_callback;
830 3256 prop->callback_arg = callback_arg;
831
832 3256 rc = globus_hashtable_insert(
833 &resource->resource_properties,
834 &prop->name,
835 prop);
836
837 3256 if (rc != GLOBUS_SUCCESS)
838 {
839 0 result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
840
841 0 goto free_qname_error;
842 }
843
844 3256 if (xsd_QName_keyeq(
845 (void *) qname,
846 (void *) globus_resource_properties_any_qname)
847 && prop->property == NULL)
848 {
849 30 result = prop->type_info->initialize(&prop->property);
850
851 30 if (result != GLOBUS_SUCCESS)
852 {
853 0 goto remove_from_hashtable_error;
854 }
855 }
856
857 3256 globus_l_resource_property_changed(
858 resource,
859 GLOBUS_TRUE,
860 qname,
861 property,
862 type_info);
863
864 3256 return GLOBUS_SUCCESS;
865
866 0 remove_from_hashtable_error:
867 0 globus_hashtable_remove(&resource->resource_properties, &prop->name);
868 0 free_qname_error:
869 0 xsd_QName_destroy_contents(&prop->name);
870 0 free_prop_error:
871 0 globus_libc_free(prop);
872 6 error:
873 6 return result;
874 }
875 /* globus_l_resource_create_property() */
876
877 /**
878 * Check to see if we can match the qname in the resource's any:any property
879 * if it is present.
880 *
881 * @param resource
882 * Resource containing the property.
883 * @param qname
884 * Name of the Resource Property element.
885 * @param property
886 * Pointer to return the value of the property.
887 * @param type_info
888 * Pointer to return the type info for this property. This may be NULL.
889 *
890 * @retval GLOBUS_SUCCESS
891 * Resource Property found and its value returned in @a property.
892 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
893 * One of the parameters to this function was NULL.
894 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
895 * The resource does not contain a property with the specified name.
896 */
897 static
898 globus_result_t
899 globus_l_resource_get_any_property(
900 globus_resource_t resource,
901 const xsd_QName * qname,
902 void ** property,
903 globus_xsd_type_info_t * info)
904 393 {
905 393 globus_result_t result = GLOBUS_SUCCESS;
906 globus_resource_property_t * prop;
907
908 393 prop = globus_hashtable_lookup(
909 &resource->resource_properties,
910 (void *) globus_resource_properties_any_qname);
911
912 393 if (prop == NULL)
913 {
914 87 result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
915
916 87 goto out;
917 }
918
919 306 if (prop->type_info == &xsd_any_info)
920 {
921 168 xsd_any * any = prop->property;
922
923 168 if (any->element != NULL &&
924 !xsd_QName_keyeq((void *) any->element, (void *) qname))
925 {
926 36 result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
927
928 36 goto out;
929 }
930 132 *property = any;
931 }
932 138 else if (prop->type_info == &xsd_any_array_info)
933 {
934 138 xsd_any_array * any_array = prop->property;
935 int i;
936
937 192 for (i = 0; i < any_array->length; i++)
938 {
939 144 if (any_array->elements[i].element == NULL)
940 {
941 18 *property = &any_array->elements[i];
942 18 break;
943 }
944 126 else if (xsd_QName_keyeq(
945 any_array->elements[i].element,
946 (void *) qname))
947 {
948 72 *property = &any_array->elements[i];
949 72 break;
950 }
951 }
952 138 if (i == any_array->length)
953 {
954 48 xsd_any * any = xsd_any_array_push(any_array);
955 48 any->any_info = &xsd_any_array_info;
956 48 *property = any;
957 }
958 }
959 270 if (info != NULL)
960 {
961 270 *info = &xsd_any_info;
962 }
963 393 out:
964 393 return result;
965 }
966 /* globus_l_resource_get_any_property() */
967
968 /**
969 * Set the value of a named resource property stored within the special
970 * "any:any" resource property.
971 *
972 * Changes the current value of the named Resource Property to be that of
973 * the @a property parameter. If the Resource Property already had a value
974 * set by a previous call to this function or
975 * #globus_resource_create_property(), the old value will be destroyed, using
976 * the functions included in the type info associated with the property. If
977 * the @a property parameter is NULL and this is in the any resource property,
978 * it will be removed.
979 *
980 * @param resource
981 * Resource containing the property.
982 * @param qname
983 * Name of the Resource Property element.
984 * @param property
985 * New value of the property.
986 *
987 * @retval GLOBUS_SUCCESS
988 * Resource Property found and its value returned in @a property.
989 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
990 * One of the parameters to this function was NULL.
991 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
992 * The resource does not contain a property with the specified name.
993 */
994 globus_result_t
995 globus_l_resource_set_any_property(
996 globus_resource_t resource,
997 const xsd_QName * qname,
998 void * property)
999 39 {
1000 39 globus_result_t result = GLOBUS_SUCCESS;
1001 39 globus_resource_property_t * prop = NULL;
1002 xsd_any * any;
1003 xsd_any_array * any_array;
1004 int i;
1005 GlobusFuncName(globus_l_resource_set_any_property);
1006
1007 39 prop = globus_hashtable_lookup(
1008 &resource->resource_properties,
1009 (void*) globus_resource_properties_any_qname);
1010
1011 39 if (prop == NULL)
1012 {
1013 3 result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
1014
1015 3 goto out;
1016 }
1017
1018 36 if (prop->type_info == &xsd_any_info)
1019 {
1020 /* Single any element */
1021 24 any = prop->property;
1022
1023 24 if (any->element == NULL ||
1024 xsd_QName_keyeq(any->element, (void *) qname))
1025 {
1026 /* The element name matches, so we'll destroy the old value */
1027 24 if (any->value != NULL)
1028 {
1029 24 any->any_info->destroy(any->value);
1030 24 any->value = NULL;
1031 }
1032 /*
1033 * Insert the new prop value if we have one; otherwise, we remove
1034 * the binding of the QName to this any.
1035 */
1036 24 if (property != NULL)
1037 {
1038 0 any->value = property;
1039 }
1040 else
1041 {
1042 24 any->value = NULL;
1043 24 if (any->element != NULL)
1044 {
1045 24 xsd_QName_destroy(any->element);
1046 24 any->element = NULL;
1047 }
1048 24 any->any_info = NULL;
1049 }
1050 }
1051 else
1052 {
1053 /* element name doesn't match */
1054 0 result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
1055
1056 0 goto out;
1057 }
1058 }
1059 else
1060 {
1061 12 assert(prop->type_info == &xsd_any_array_info);
1062 12 any_array = prop->property;
1063
1064 /* The value is an array of anys. We'll look for the one which
1065 * matches our qname, and replace its contents with the new value.
1066 * if property is null, we'll remove it from the array altogether
1067 */
1068 12 for (i = 0; i < any_array->length; i++)
1069 {
1070 12 any = &any_array->elements[i];
1071
1072 12 if (any->element != NULL &&
1073 xsd_QName_keyeq(any->element, (void *) qname))
1074 {
1075 /* found a match */
1076 12 if (any->value != NULL)
1077 {
1078 /* old value -- gone! */
1079 12 any->any_info->destroy(any->value);
1080 12 any->value = NULL;
1081 }
1082 12 if (property != NULL)
1083 {
1084 /* replace with new value */
1085 0 any->value = property;
1086 }
1087 else
1088 {
1089 /* delete binding for this QName */
1090 12 xsd_QName_destroy(any->element);
1091 12 any->element = NULL;
1092
1093 12 if (i + 1 < any_array->length)
1094 {
1095 /* pop this array element out of the array */
1096 12 memmove(
1097 &any_array->elements[i],
1098 &any_array->elements[i+1],
1099 sizeof(any_array->elements[i]) *
1100 (any_array->length - (i + 1)));
1101 }
1102 /* And clear value at the tail of this array */
1103 12 memset(&any_array->elements[any_array->length-1],
1104 0,
1105 sizeof(any_array->elements[i]));
1106 12 any_array->length--;
1107 }
1108 12 break; /* only one match will be possible */
1109 }
1110 }
1111 }
1112 39 out:
1113 39 return result;
1114 }
1115 /* globus_l_resource_set_any_property() */
1116
1117 static
1118 void
1119 globus_l_resource_property_changed(
1120 globus_resource_t resource,
1121 globus_bool_t new_property,
1122 const xsd_QName * qname,
1123 void * value,
1124 const globus_xsd_type_info_t type_info)
1125 4638 {
1126 globus_list_t * tmp;
1127 globus_i_resource_property_changed_callback_t *
1128 callback;
1129 GlobusFuncName(globus_l_resource_property_changed);
1130
1131 4638 if (resource->property_changed_callbacks == NULL)
1132 {
1133 3752 goto out;
1134 }
1135
1136 886 tmp = resource->property_changed_callbacks;
1137
1138 2658 while (! globus_list_empty(tmp))
1139 {
1140 886 callback = globus_list_first(tmp);
1141 886 tmp = globus_list_rest(tmp);
1142
1143 886 callback->callback(
1144 callback->callback_arg,
1145 resource,
1146 new_property,
1147 qname,
1148 value,
1149 type_info);
1150 }
1151 4638 out:
1152 return;
1153 }
1154 /* globus_l_resource_property_changed() */
1155
1156 static
1157 int
1158 globus_l_resource_callback_equal(
1159 void * datum,
1160 void * callback)
1161 0 {
1162 globus_i_resource_property_changed_callback_t *
1163 0 callback_info = datum;
1164
1165 0 return (callback_info->callback == callback);
1166 }
1167 /* globus_l_resource_callback_equal() */