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 617314 {
108 617314     globus_result_t                     result = GLOBUS_SUCCESS;
109 617314     globus_resource_property_t *        prop = NULL;
110 617314     GlobusFuncName(globus_resource_get_property);
111
112 617314     if (resource == NULL || qname == NULL || property == NULL)
113     {
114 3         return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
115     }
116
117 617311     *property = NULL;
118
119 617311     prop = globus_hashtable_lookup(
120             &resource->resource_properties,
121             (void *) qname);
122
123 617311     if (prop != NULL)
124     {
125 617184         if (prop->get_callback != NULL)
126         {
127 370             prop->get_callback(prop->callback_arg, qname, property);
128
129 370             if (prop->property != NULL)
130             {
131 307                 prop->type_info->destroy(prop->property);
132             }
133 370             prop->property = *property;
134         }
135         else
136         {
137 616814             *property = prop->property;
138         }
139 617184         if (type_info != NULL)
140         {
141 617138             (*type_info) = prop->type_info;
142         }
143     }
144     else
145     {
146 127         result = globus_l_resource_get_any_property(
147                 resource,
148                 qname,
149                 property,
150                 type_info);
151
152 127         if (result != GLOBUS_SUCCESS)
153         {
154 617311             goto out;
155         }
156     }
157
158 out:
159 617311     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 336 {
193 336     globus_result_t                     result = GLOBUS_SUCCESS;
194 336     globus_resource_property_t *        prop = NULL;
195 336     globus_bool_t                       allowed = GLOBUS_TRUE;
196 336     GlobusFuncName(globus_resource_set_property);
197
198 336     if (resource == NULL || qname == NULL)
199     {
200 2         return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
201     }
202
203 334     prop = globus_hashtable_lookup(
204             &resource->resource_properties,
205             (void*) qname);
206
207 334     if (prop != NULL)
208     {
209 321         if (prop->set_callback != NULL)
210         {
211 0             allowed = prop->set_callback(prop->callback_arg, qname, property);
212         }
213
214 321         if (! allowed)
215         {
216 0             result = GLOBUS_RESOURCE_ERROR_CHANGE_DENIED(qname);
217
218 0             goto out;
219         }
220
221 321         if (prop->property != NULL && prop->type_info->destroy != NULL)
222         {
223 263             prop->type_info->destroy(prop->property);
224         }
225
226 321         prop->property = property;
227     }
228     else
229     {
230 13         result = globus_l_resource_set_any_property(
231                 resource,
232                 qname,
233                 property);
234     }
235
236 334     if (result == GLOBUS_SUCCESS)
237     {
238         /* prop may be null if set_any_property is called with a NULL
239          * property value
240          */
241 333         globus_l_resource_property_changed(
242             resource,
243             GLOBUS_FALSE,
244             qname,
245             property,
246             prop ? prop->type_info : NULL);
247     }
248 out:
249 334     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 754 {
289 754     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 198 {
349 198     GlobusFuncName(globus_resource_create_property_callback);
350
351 198     if (get_callback == NULL || set_callback == NULL)
352     {
353 2         return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
354     }
355
356 196     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 372 {
386 372     globus_xsd_type_info_t              type_info;
387 372     void *                              property;
388 372     globus_result_t                     result = GLOBUS_SUCCESS;
389 372     GlobusFuncName(globus_resource_property_changed);
390
391 372     if (resource == NULL || qname == NULL)
392     {
393 0         return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
394     }
395
396 372     if (resource->property_changed_callbacks == NULL)
397     {
398 0         goto out;
399     }
400
401 372     result = globus_resource_get_property(
402             resource,
403             qname,
404             &property,
405             &type_info);
406
407 372     if (result != GLOBUS_SUCCESS)
408     {
409 0         goto out;
410     }
411
412 372     globus_l_resource_property_changed(
413             resource,
414             GLOBUS_FALSE,
415             qname,
416             property,
417             type_info);
418
419 out:
420 372     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 94 {
447 94     globus_result_t                     result = GLOBUS_SUCCESS;
448 94     int                                 rc;
449 94     globus_list_t *                     tmp;
450     globus_i_resource_property_changed_callback_t *
451 94                                         callback_info;
452 94     GlobusFuncName(globus_resource_add_property_changed_callback);
453
454 94     if (resource == NULL || callback == NULL)
455     {
456 0         return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
457     }
458
459 94     tmp = globus_list_search_pred(
460             resource->property_changed_callbacks,
461             globus_l_resource_callback_equal,
462             callback);
463 94     if (tmp != NULL)
464     {
465 0         goto out;
466     }
467 94     callback_info = globus_libc_malloc(
468             sizeof(globus_i_resource_property_changed_callback_t));
469 94     if (callback_info == NULL)
470     {
471 0         result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
472
473 0         goto out;
474     }
475
476 94     callback_info->callback = callback;
477 94     callback_info->callback_arg = callback_arg;
478
479 94     rc = globus_list_insert(
480             &resource->property_changed_callbacks,
481             callback_info);
482
483 94     if (rc != GLOBUS_SUCCESS)
484     {
485 0         globus_libc_free(callback_info);
486
487 0         result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
488
489         goto out;
490     }
491
492 out:
493 94     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 0     globus_list_t *                     tmp;
506     globus_i_resource_property_changed_callback_t *
507 0                                         callback_info;
508 0     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 6 {
565 6     globus_resource_property_t *        prop = NULL;
566 6     globus_result_t                     result = GLOBUS_SUCCESS;
567 6     GlobusFuncName(globus_resource_delete_property);
568
569 6     if (resource == NULL || qname == NULL || property == NULL ||
570             type_info == NULL)
571     {
572 4         return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
573     }
574
575 2     if (resource->resource_properties != NULL)
576     {
577 2         prop = globus_hashtable_remove(
578                 &resource->resource_properties,
579                 (void*) qname);
580     }
581
582 2     if (prop == NULL)
583     {
584 1         result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
585
586 1         goto out;
587     }
588
589 1     *property = prop->property;
590 1     *type_info = prop->type_info;
591
592 1     globus_free(prop->name.Namespace);
593 1     globus_free(prop->name.local);
594 1     globus_free(prop);
595 out:
596
597 2     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 6 {
626 6     globus_resource_property_t *        prop = NULL;
627 6     globus_result_t                     result = GLOBUS_SUCCESS;
628 6     GlobusFuncName(globus_resource_destroy_property);
629
630 6     if (resource == NULL || qname == NULL)
631     {
632 2         return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
633     }
634
635 4     if (resource->resource_properties != NULL)
636     {
637 4         prop = globus_hashtable_remove(
638                 &resource->resource_properties,
639                 (void *) qname);
640     }
641
642 4     if (prop == NULL)
643     {
644 1         result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
645 1         goto out;
646     }
647
648 3     if (prop->property != NULL)
649     {
650 1         prop->type_info->destroy(prop->property);
651     }
652
653 3     free(prop->name.Namespace);
654 3     free(prop->name.local);
655 3     free(prop);
656
657 out:
658 4     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 114 {
667 114     globus_result_t                     result;
668 114     globus_resource_property_t *        tmp;
669 114     xsd_QName *                         name;
670
671 114     if (property_names == NULL)
672     {
673 0         return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
674
675 114         goto out;
676     }
677
678 114     if (resource == NULL)
679     {
680 0         return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
681
682 114         goto nullify_property_names_out;
683     }
684
685 114     result = xsd_QName_array_init(property_names);
686
687 114     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 114     tmp = globus_hashtable_first(&resource->resource_properties);
695
696 740     while (tmp != NULL)
697     {
698 626         name = xsd_QName_array_push(*property_names);
699
700 626         if (name == NULL)
701         {
702 0             result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
703
704 0             goto free_array_out;
705         }
706
707 626         result = xsd_QName_copy_contents(name, &tmp->name);
708
709 626         if (result != GLOBUS_SUCCESS)
710         {
711 0             result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
712
713 0             goto free_array_out;
714         }
715
716 626         tmp = globus_hashtable_next(&resource->resource_properties);
717     }
718
719 114     if (result != GLOBUS_SUCCESS)
720     {
721 free_array_out:
722 0         xsd_QName_array_destroy(*property_names);
723 nullify_property_names_out:
724 0         *property_names = NULL;
725     }
726 out:
727 114     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 950 {
778 950     globus_resource_property_t *        prop;
779 950     globus_result_t                     result;
780 950     int                                 rc;
781 950     GlobusFuncName(globus_l_resource_create_property);
782
783 950     if (resource == NULL || qname == NULL || type_info == NULL)
784     {
785 6         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 944     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 944     prop = globus_hashtable_lookup(
803             &resource->resource_properties,
804             (void *) qname);
805
806 944     if (prop != NULL)
807     {
808 2         result = GLOBUS_RESOURCE_ERROR_DUPLICATE_PROPERTY(qname);
809
810 2         goto error;
811     }
812 942     prop = malloc(sizeof(struct globus_resource_property_s));
813
814 942     if (prop == NULL)
815     {
816 0         result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
817
818 0         goto error;
819     }
820     
821 942     result = xsd_QName_copy_contents(&prop->name, qname);
822 942     if(result != GLOBUS_SUCCESS)
823     {
824 0         goto free_prop_error;
825     }
826 942     prop->type_info = type_info;
827 942     prop->property = property;
828 942     prop->get_callback = get_callback;
829 942     prop->set_callback = set_callback;
830 942     prop->callback_arg = callback_arg;
831
832 942     rc = globus_hashtable_insert(
833             &resource->resource_properties,
834             &prop->name,
835             prop);
836
837 942     if (rc != GLOBUS_SUCCESS)
838     {
839 0         result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
840
841 0         goto free_qname_error;
842     }
843
844 942     if (xsd_QName_keyeq(
845                 (void *) qname,
846                 (void *) globus_resource_properties_any_qname)
847         && prop->property == NULL)
848     {
849 10         result = prop->type_info->initialize(&prop->property);
850
851 10         if (result != GLOBUS_SUCCESS)
852         {
853 0             goto remove_from_hashtable_error;
854         }
855     }
856
857 942     globus_l_resource_property_changed(
858             resource,
859             GLOBUS_TRUE,
860             qname,
861             property,
862             type_info);
863
864 942     return GLOBUS_SUCCESS;
865
866 remove_from_hashtable_error:
867 0     globus_hashtable_remove(&resource->resource_properties, &prop->name);
868 free_qname_error:
869 0     xsd_QName_destroy_contents(&prop->name);
870 free_prop_error:
871 0     globus_libc_free(prop);
872 error:
873 2     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 127 {
905 127     globus_result_t                     result = GLOBUS_SUCCESS;
906 127     globus_resource_property_t *        prop;
907
908 127     prop = globus_hashtable_lookup(
909             &resource->resource_properties,
910             (void *) globus_resource_properties_any_qname);
911
912 127     if (prop == NULL)
913     {
914 25         result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
915
916 25         goto out;
917     }
918
919 102     if (prop->type_info == &xsd_any_info)
920     {
921 56         xsd_any *                   any = prop->property;
922
923 56         if (any->element != NULL &&
924             !xsd_QName_keyeq((void *) any->element, (void *) qname))
925         {
926 12             result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
927
928 12             goto out;
929         }
930 44         *property = any;
931     }
932 46     else if (prop->type_info == &xsd_any_array_info)
933     {
934 46         xsd_any_array *             any_array = prop->property;
935 46         int i;
936
937 64         for (i = 0; i < any_array->length; i++)
938         {
939 48             if (any_array->elements[i].element == NULL)
940             {
941 6                 *property = &any_array->elements[i];
942 6                 break;
943             }
944 42             else if (xsd_QName_keyeq(
945                         any_array->elements[i].element,
946                         (void *) qname))
947             {
948 24                 *property = &any_array->elements[i];
949 24                 break;
950             }
951         }
952 46         if (i == any_array->length)
953         {
954 16             xsd_any * any = xsd_any_array_push(any_array);
955 16             any->any_info = &xsd_any_array_info;
956 16             *property = any;
957         }
958     }
959 90     if (info != NULL)
960     {
961 90         *info = &xsd_any_info;
962     }
963 out:
964 127     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 13 {
1000 13     globus_result_t                     result = GLOBUS_SUCCESS;
1001 13     globus_resource_property_t *        prop = NULL;
1002 13     xsd_any *                           any;
1003 13     xsd_any_array *                     any_array;
1004 13     int                                 i;
1005 13     GlobusFuncName(globus_l_resource_set_any_property);
1006
1007 13     prop = globus_hashtable_lookup(
1008             &resource->resource_properties,
1009             (void*) globus_resource_properties_any_qname);
1010
1011 13     if (prop == NULL)
1012     {
1013 1         result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
1014
1015 1         goto out;
1016     }
1017
1018 12     if (prop->type_info == &xsd_any_info)
1019     {
1020         /* Single any element */
1021 8         any = prop->property;
1022
1023 8         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 8             if (any->value != NULL)
1028             {
1029 8                 any->any_info->destroy(any->value);
1030 8                 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 8             if (property != NULL)
1037             {
1038 0                 any->value = property;
1039             }
1040             else
1041             {
1042 8                 any->value = NULL;
1043 8                 if (any->element != NULL)
1044                 {
1045 8                     xsd_QName_destroy(any->element);
1046 8                     any->element = NULL;
1047                 }
1048 8                 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 4         assert(prop->type_info == &xsd_any_array_info);
1062 4         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 4         for (i = 0; i < any_array->length; i++)
1069         {
1070 4             any = &any_array->elements[i];
1071
1072 4             if (any->element != NULL &&
1073                 xsd_QName_keyeq(any->element, (void *) qname))
1074             {
1075                 /* found a match */
1076 4                 if (any->value != NULL)
1077                 {
1078                     /* old value -- gone! */
1079 4                     any->any_info->destroy(any->value);
1080 4                     any->value = NULL;
1081                 }
1082 4                 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 4                     xsd_QName_destroy(any->element);
1091 4                     any->element = NULL;
1092
1093 4                     if (i + 1 < any_array->length)
1094                     {
1095                         /* pop this array element out of the array */
1096 4                         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 4                     memset(&any_array->elements[any_array->length-1],
1104                             0,
1105                             sizeof(any_array->elements[i]));
1106 4                     any_array->length--;
1107                 }
1108 4                 break; /* only one match will be possible */
1109             }
1110         }
1111     }
1112 out:
1113 13     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 1647 {
1126 1647     globus_list_t *                     tmp;
1127     globus_i_resource_property_changed_callback_t *
1128 1647                                         callback;
1129 1647     GlobusFuncName(globus_l_resource_property_changed);
1130
1131 1647     if (resource->property_changed_callbacks == NULL)
1132     {
1133 1232         goto out;
1134     }
1135
1136 415     tmp = resource->property_changed_callbacks;
1137
1138 830     while (! globus_list_empty(tmp))
1139     {
1140 415         callback = globus_list_first(tmp);
1141 415         tmp = globus_list_rest(tmp);
1142
1143 415         callback->callback(
1144                 callback->callback_arg,
1145                 resource,
1146                 new_property,
1147                 qname,
1148                 value,
1149                 type_info);
1150     }
1151 out:
1152 1647     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() */