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_common.h"
18 #include "globus_i_xsd.h"
19 #include "globus_i_xsd_type_registry.h"
20 #include "globus_i_xsd_type_info.h"
21 #include "globus_soap_message_utils.h"
22 #include "globus_soap_message.h"
23
24 /**
25  * Initialize a new type registry.
26  * @ingroup globus_xsd_type_registry
27  *
28  * @param registry
29  *     New type registry.
30  *
31  * @retval GLOBUS_SUCCESS
32  *     Registry initialized.
33  * @retval GLOBUS_MESSAGE_ERROR_TYPE_NULL_PARAM
34  *     The @a registry parameter was NULL.
35  * @retval GLOBUS_MESSAGE_ERROR_TYPE_OUT_OF_MEMORY
36  *     Unable to allocate registry data.
37  *
38  * @see globus_xsd_type_registry_destroy()
39  */
40 globus_result_t
41 globus_xsd_type_registry_init(
42     globus_xsd_type_registry_t *        registry)
43 819 {
44 819     globus_result_t                     result;
45 819     struct globus_xsd_type_registry_s * p;
46 819     int                                 rc;
47 819     GlobusFuncName(globus_xsd_type_registry_init);
48 819     GlobusSoapMessageDebugEnter();
49
50 819     if (registry == NULL)
51     {
52 0         result = GlobusSoapMessageErrorNullParam;
53
54 0         goto error;
55     }
56 819     *registry = NULL;
57
58 819     p = globus_libc_malloc(sizeof(struct globus_xsd_type_registry_s));
59 819     if (p == NULL)
60     {
61 0         result = GlobusSoapMessageErrorOutOfMemory;
62
63 0         goto error;
64     }
65
66 819     rc = globus_hashtable_init(
67             &p->table,
68             257,
69             xsd_QName_hash,
70             xsd_QName_keyeq);
71
72 819     if (rc != GLOBUS_SUCCESS)
73     {
74 0         result = GlobusSoapMessageErrorOutOfMemory;
75
76 0         goto free_p_error;
77     }
78
79 819     globus_mutex_init(&p->lock, NULL);
80 819     *registry = p;
81
82 819     GlobusSoapMessageDebugExit();
83 819     return GLOBUS_SUCCESS;
84
85 free_p_error:
86 0     globus_libc_free(p);
87 error:
88 0     GlobusSoapMessageDebugExit();
89 0     return result;
90 }
91 /* globus_xsd_type_registry_init() */
92
93 /**
94  * Destroy a type registry.
95  * @ingroup globus_xsd_type_registry
96  *
97  * @param registry
98  *     Type registry to destroy.
99  *
100  * @retval GLOBUS_SUCCESS
101  *     Registry destroyed.
102  * @retval GLOBUS_MESSAGE_ERROR_TYPE_NULL_PARAM
103  *     The @a registry parameter was NULL.
104  *
105  * @see globus_xsd_type_registry_init()
106  * @see globus_xsd_type_registry_clear()
107  */
108 globus_result_t
109 globus_xsd_type_registry_destroy(
110     globus_xsd_type_registry_t          registry)
111 582 {
112 582     globus_result_t                     result;
113 582     GlobusFuncName(globus_xsd_type_registry_destroy);
114 582     GlobusSoapMessageDebugEnter();
115
116 582     result = globus_xsd_type_registry_clear(registry);
117
118 582     if (result == GLOBUS_SUCCESS)
119     {
120 582         globus_hashtable_destroy(&registry->table);
121 582         globus_mutex_destroy(&registry->lock);
122 582         globus_libc_free(registry);
123     }
124
125 582     GlobusSoapMessageDebugExit();
126 582     return result;
127 }
128 /* globus_xsd_type_registry_destroy() */
129
130 /**
131  * Insert a type into the registry.
132  * @ingroup globus_xsd_type_registry
133  *
134  * If an existing type mapping is registered for the specified type, it
135  * is replaced with the new type. The old type is returned in value pointed to
136  * by the @a old_info  parameter.
137  *
138  * @param registry
139  *     Registry to modify.
140  * @param info
141  *     Information about the type.
142  * @param old_info
143  *     Pointer to be set to the value of the previous info for this type.
144  *     May be NULL if the caller is not interested in this.
145  *
146  * @retval GLOBUS_SUCCESS
147  *     Type mapping added
148  * @retval GLOBUS_MESSAGE_ERROR_TYPE_NULL_PARAM
149  *     The @a registry or @a info  parameter was NULL.
150  *
151  * @see globus_xsd_type_registry_remove()
152  * @see globus_xsd_type_registry_get()
153  */
154 globus_result_t
155 globus_xsd_type_registry_insert(
156     globus_xsd_type_registry_t          registry,
157     globus_xsd_type_info_t              info,
158     globus_xsd_type_info_t *            old_info)
159 79044 {
160 79044     globus_result_t                     result;
161 79044     globus_xsd_type_info_t              p;
162 79044     int                                 rc;
163 79044     GlobusFuncName(globus_xsd_type_registry_insert);
164 79044     GlobusSoapMessageDebugEnter();
165
166 79044     if (registry == NULL || info == NULL)
167     {
168 0         result = GlobusSoapMessageErrorNullParam;
169
170 0         goto error;
171     }
172
173 79044     rc = globus_mutex_lock(&registry->lock);
174 79044     if (rc != GLOBUS_SUCCESS)
175     {
176 0         result = GlobusSoapMessageErrorOutOfMemory;
177
178 0         goto error;
179     }
180     
181 79044     p = globus_hashtable_lookup(&registry->table, info->type);
182 79044     if(p == info)
183     {
184 5498         if(old_info)
185         {
186 0             *old_info = p;
187         }
188 0         goto exit;
189     }
190  
191 73546     p = globus_hashtable_remove(&registry->table, info->type);
192
193 73546     if (old_info)
194     {
195 38         *old_info = p;
196     }
197
198 73546     rc = globus_hashtable_insert(&registry->table, info->type, info);
199
200 73546     if (rc != GLOBUS_SUCCESS)
201     {
202 0         result = GlobusSoapMessageErrorOutOfMemory;
203
204 0         goto unlock_error;
205     }
206
207  exit:
208 79044     globus_mutex_unlock(&registry->lock);
209
210 79044     GlobusSoapMessageDebugExit();
211 79044     return GLOBUS_SUCCESS;
212
213 unlock_error:
214 0     globus_mutex_unlock(&registry->lock);
215 error:
216 0     GlobusSoapMessageDebugExit();
217 0     return result;
218 }
219 /* globus_xsd_type_registry_insert() */
220
221 /**
222  * Remove a type from the registry.
223  * @ingroup globus_xsd_type_registry
224  *
225  * @param registry
226  *     Registry to modify.
227  * @param name
228  *     Name of the type to be unregistered.
229  * @param info
230  *     Pointer to be set to the previously registred type information. May be
231  *     NULL if the caller doesn't want that type info.
232  *
233  * @retval GLOBUS_SUCCESS
234  *     Type mapping removed.
235  * @retval GLOBUS_MESSAGE_ERROR_TYPE_NULL_PARAM
236  *     The @a registry or @a name parameter was NULL.
237  *
238  * @see globus_xsd_type_registry_replace()
239  * @see globus_xsd_type_registry_remove()
240  * @see globus_xsd_type_registry_get()
241  */
242 globus_result_t
243 globus_xsd_type_registry_remove(
244     globus_xsd_type_registry_t          registry,
245     const xsd_QName *                   name,
246     globus_xsd_type_info_t *            info)
247 10010 {
248 10010     globus_result_t                     result;
249 10010     globus_xsd_type_info_t              tmp;
250 10010     GlobusFuncName(globus_xsd_type_registry_remove);
251 10010     GlobusSoapMessageDebugEnter();
252
253 10010     if (registry == NULL || name == NULL)
254     {
255 0         result = GlobusSoapMessageErrorNullParam;
256
257 0         goto error;
258     }
259
260 10010     globus_mutex_lock(&registry->lock);
261 10010     tmp = globus_hashtable_remove(&registry->table, (void *) name);
262
263 10010     if (info != NULL)
264     {
265 0         *info = tmp;
266     }
267 10010     globus_mutex_unlock(&registry->lock);
268     
269 10010     GlobusSoapMessageDebugExit();
270 10010     return GLOBUS_SUCCESS;
271 error:
272 0     GlobusSoapMessageDebugExit();
273 0     return result;
274 }
275 /* globus_xsd_type_registry_remove() */
276
277 /**
278  * Remove all entries from a type registry
279  * @ingroup globus_xsd_type_registry
280  *
281  * @param registry
282  *     Registry to clear.
283  *
284  * @retval GLOBUS_SUCCESS
285  *     Type mapping removed.
286  * @retval GLOBUS_MESSAGE_ERROR_TYPE_NULL_PARAM
287  *     The @a registry parameter was NULL.
288  * @retval GLOBUS_MESSAGE_ERROR_TYPE_OUT_OF_MEMORY
289  *     Insufficient memory to clear registry.
290  */
291 globus_result_t
292 globus_xsd_type_registry_clear(
293     globus_xsd_type_registry_t          registry)
294 582 {
295 582     int                                 rc;
296 582     globus_result_t                     result;
297 582     globus_list_t *                     tmp_list;
298 582     globus_xsd_type_info_t              p;
299 582     GlobusFuncName(globus_xsd_type_registry_clear);
300 582     GlobusSoapMessageDebugEnter();
301
302 582     if (registry == NULL)
303     {
304 0         result = GlobusSoapMessageErrorNullParam;
305
306 0         goto error;
307     }
308 582     rc = globus_mutex_lock(&registry->lock);
309 582     if (rc != GLOBUS_SUCCESS)
310     {
311 0         result = GlobusSoapMessageErrorOutOfMemory;
312
313 0         goto error;
314     }
315 582     rc = globus_hashtable_to_list(&registry->table, &tmp_list);
316 582     if (rc != GLOBUS_SUCCESS)
317     {
318 0         result = GlobusSoapMessageErrorNullParam;
319
320 0         goto unlock_error;
321     }
322 38186     while (!globus_list_empty(tmp_list))
323     {
324 37604         p = globus_list_remove(&tmp_list, tmp_list);
325
326 37604         globus_assert(p);
327
328 37604         globus_hashtable_remove(&registry->table, p->type);
329     }
330
331 582     globus_mutex_unlock(&registry->lock);
332
333 582     GlobusSoapMessageDebugExit();
334 582     return GLOBUS_SUCCESS;
335
336
337 unlock_error:
338 0     globus_mutex_unlock(&registry->lock);
339 error:
340 0     GlobusSoapMessageDebugExit();
341 0     return result;
342 }
343 /* globus_xsd_type_registry_clear() */
344
345 /**
346  * Look up a QName in a type registry
347  * @ingroup globus_xsd_type_registry
348  *
349  * Locate the type mapping for a given QName in a type registry and return it.
350  *
351  * @param registry
352  *     Registry to query.
353  * @param name
354  *     QName of the type to look up
355  * @param info
356  *     Return parameter will be set to the type mapping for the given
357  *     @a name if present.
358  *
359  * @retval GLOBUS_SUCCESS
360  *     The type mapping lookup was processed. The @info value may be NULL
361  *     if no mapping for the given type is in the registry.
362  * @retval GLOBUS_MESSAGE_ERROR_TYPE_NULL_PARAM
363  *     The @a registry, @a name, or @a info parameter was NULL.
364  * @retval GLOBUS_MESSAGE_ERROR_TYPE_OUT_OF_MEMORY
365  *     Insufficient memory to get registry value.
366  */
367 globus_result_t
368 globus_xsd_type_registry_get(
369     globus_xsd_type_registry_t          registry,
370     const xsd_QName *                   name,
371     globus_xsd_type_info_t *            info)
372 747710 {
373 747710     globus_result_t                     result;
374 747710     int                                 rc;
375 747710     GlobusFuncName(globus_xsd_type_registry_get);
376 747710     GlobusSoapMessageDebugEnter();
377
378 747710     if (registry == NULL || name == NULL || info == NULL)
379     {
380 0         result = GlobusSoapMessageErrorNullParam;
381
382 0         goto error;
383     }
384 747710     rc = globus_mutex_lock(&registry->lock);
385 747710     if (rc != GLOBUS_SUCCESS)
386     {
387 0         result = GlobusSoapMessageErrorOutOfMemory;
388
389 0         goto error;
390     }
391 747710     *info = globus_hashtable_lookup(&registry->table, (void *) name);
392
393 747710     globus_mutex_unlock(&registry->lock);
394
395 747710     GlobusSoapMessageDebugExit();
396 747710     return GLOBUS_SUCCESS;
397 error:
398 0     GlobusSoapMessageDebugExit();
399 0     return result;
400 }
401 /* globus_xsd_type_registry_get() */
402
403 /**
404  * Add XML schema base types to a registry
405  * @ingroup globus_xsd_type_registry
406  *
407  * Inserts the XML schema basic types into the given type registry.
408  *
409  * @param registry
410  *     Registry to update.
411  *
412  * @retval GLOBUS_SUCCESS
413  *     Type mappings added.
414  * @retval GLOBUS_MESSAGE_ERROR_TYPE_NULL_PARAM
415  *     The @a registry parameter was NULL.
416  * @retval GLOBUS_MESSAGE_ERROR_TYPE_OUT_OF_MEMORY
417  *     Insufficient memory to add types to registry.
418  */
419 globus_result_t
420 globus_xsd_type_registry_add_base_types(
421     globus_xsd_type_registry_t          registry)
422 602 {
423 602     globus_result_t                     result = GLOBUS_SUCCESS;
424 602     int                                 i;
425     static globus_xsd_type_info_t       builtin_types[] =
426     {
427         &xsd_ID_info,
428         &xsd_IDREF_info,
429         &xsd_IDREFS_info,
430         &xsd_ENTITY_info,
431         &xsd_ENTITIES_info,
432         &xsd_NCName_info,
433         &xsd_NMTOKEN_info,
434         &xsd_NMTOKENS_info,
435         &xsd_NOTATION_info,
436         &xsd_Name_info,
437         &xsd_QName_info,
438         &xsd_anyURI_info,
439         &xsd_base64Binary_info,
440         &xsd_boolean_info,
441         &xsd_byte_info,
442         &xsd_date_info,
443         &xsd_dateTime_info,
444         &xsd_decimal_info,
445         &xsd_double_info,
446         &xsd_duration_info,
447         &xsd_float_info,
448         &xsd_gDay_info,
449         &xsd_gMonth_info,
450         &xsd_gMonthDay_info,
451         &xsd_gYear_info,
452         &xsd_gYearMonth_info,
453         &xsd_hexBinary_info,
454         &xsd_int_info,
455         &xsd_integer_info,
456         &xsd_language_info,
457         &xsd_long_info,
458         &xsd_negativeInteger_info,
459         &xsd_nonNegativeInteger_info,
460         &xsd_nonPositiveInteger_info,
461         &xsd_normalizedString_info,
462         &xsd_positiveInteger_info,
463         &xsd_short_info,
464         &xsd_string_info,
465         &xsd_time_info,
466         &xsd_token_info,
467         &xsd_unsignedByte_info,
468         &xsd_unsignedInt_info,
469         &xsd_unsignedLong_info,
470         &xsd_unsignedShort_info,
471         NULL
472 602     };
473
474 602     GlobusFuncName(globus_xsd_type_registry_add_base_types);
475 602     GlobusSoapMessageDebugEnter();
476
477 27090     for (i = 0; builtin_types[i] != NULL; i++)
478     {
479 26488         result = globus_xsd_type_registry_insert(
480                     registry,
481                     builtin_types[i],
482                     NULL);
483 26488         if(result != GLOBUS_SUCCESS)
484         {
485 0             break;
486         }
487     }
488
489 602     GlobusSoapMessageDebugExit();
490 602     return result;
491 }
492 /* globus_xsd_type_registry_add_base_types() */
493
494 /**
495  * Dump the contents of an xsd type registry to the debug stream
496  * @ingroup globus_xsd_type_registry
497  *
498  * @param registry
499  *     The registry to dump.
500  *
501  * @retval GLOBUS_SUCCESS
502  *     Registry successfully dumped.
503  * @retval GLOBUS_MESSAGE_ERROR_TYPE_NULL_PARAM
504  *     The @a registry parameter was NULL.
505  * @retval GLOBUS_MESSAGE_ERROR_TYPE_OUT_OF_MEMORY
506  *     Insufficient memory to dump registry.
507  */
508 globus_result_t
509 globus_xsd_type_registry_dump(
510     globus_xsd_type_registry_t               registry)
511 0 {
512 0     globus_result_t                     result = GLOBUS_SUCCESS;
513 0     globus_xsd_type_info_t              info;
514 0     int                                 rc = 0;
515 0     GlobusFuncName(globus_xsd_type_registry_dump);
516 0     GlobusSoapMessageDebugEnter();
517
518 0     rc = globus_mutex_lock(&registry->lock);
519 0     if (rc != GLOBUS_SUCCESS)
520     {
521 0         result = GlobusSoapMessageErrorOutOfMemory;
522 0         goto error;
523     }
524     
525 0     info = globus_hashtable_first(&registry->table);
526
527 0     while(info)
528     {
529 0         GlobusSoapMessageDebugPrintf(
530             GLOBUS_SOAP_MESSAGE_DEBUG_REGISTRY,
531             ("{%s}%s\n",
532             info->type->Namespace,
533             info->type->local));
534         
535 0         info = globus_hashtable_next(&registry->table);
536     }
537
538 0     rc = globus_mutex_unlock(&registry->lock);
539 0     if(rc != GLOBUS_SUCCESS)
540     {
541 0         result = GlobusSoapMessageErrorOutOfMemory;
542         goto error;
543     }
544
545  error:
546
547 0     GlobusSoapMessageDebugExit();
548 0     return result;
549 }