Usage scenarios

Here we provide some scenarios for using C WS-Core that aren't described in the tutorials.

1. Using Wildcards

Both clients and services may need to create or parse instances of xsd_any or xsd_anyType types. This is necessary when the XML schema defines a type that includes the xsd_any or xsd_anyType as a type for one of its elements, such as:

 <xsd:complexType name="TemporalType"> <xsd:sequence>
        <xsd:any minOccurs="1" maxOccurs="1" processContents="lax" />
        </xsd:sequence> </xsd:complexType> <xsd:element
        name="Temporal" type="tns:TemporalType"/> 

The content of an instance of TemporalType is not restricted by the schema definition, and so must be handled specially at runtime. For serialization and deserialization of wildcard elements, a special global variable of type globus_xsd_type_info_t is associated with each type that can be set on the wildcard. For example, if a user wanted an instance of TemporalType to contain an instance of an xsd:dateTime, the any field must be filled in properly. The following bit of C code does this:

 time_t current; TemporalType temp; xsd_QName * element; xsd_dateTime * time; /* this
        is just a struct tm */ ... result = TemporalType_init_contents(&temp); /* check
        result */ temp.any.any_info = &xsd_dateTime_info; result =
        xsd_dateTime_init(&time); /* check result */ current = time(NULL); /* get the
        current time */ result = xsd_dateTime_copy_contents( time, (xsd_dateTime
        *)localtime(&current)); /* check result */ temp.any.value = (void *)time; result =
        xsd_QName_init(&element); /* check result */ element->Namespace =
        globus_libc_strdup("http://temporal.com"); element->local = globus_libc_strdup("Time");
        temp.any.element = element; /* now we can serialize it */ result = TemporalType_serialize(
        &Temporal_qname, temp, handle, 0); /* check result */ 

This serializes the TemporalType to the contain the current timestamp. The resulting serialized elements would look like this:

          <time:Temporal xmlns:time="http://temporal.com">
          <time:Time>Mon Apr 17 10:14:22 CDT 2005</time:Time>
          </time:Temporal> 

If we want to serialize it to a string of the current day of the week, we would do this:

 time_t current; TemporalType temp;
          xsd_QName * element; xsd_string * day; /* this is just a pointer to char * */ ... result =
          TemporalType_init_contents(&temp); /* check result */ temp.any.any_info =
          &xsd_string_info; result = xsd_string_init_cstr(&day, "Monday"); /* check
          result */ temp.any.value = (void *)day; result = xsd_QName_init(&element); /*
          check result */ element->Namespace = globus_libc_strdup("http://temporal.com");
          element->local = globus_libc_strdup("Day"); temp.any.element = element; /* now we can
          serialize it */ result = TemporalType_serialize( &Temporal_qname, temp, handle,
          0); /* check result */ 

This allows us to serialize the temporal time element as the day of the week. The resulting serialized elements for this code would look like this:

          <time:Temporal xmlns:time="http://temporal.com">
          <time:Day>Monday</time:Day> </time:Temporal>
        

So this allows us to inject types into wildcard elements at runtime, and demonstrates how to serialize those wildcards.

For deserialization of wildcard types, a registry is used to lookup the actual type of the element based on QName or the xsi:type attribute. The registry contains key/value pairs of QName to globus_xsd_type_info_t structures. These structures contain the appropriate information about deserializing the type.

2. Using Asynchronous client stubs

A client may wish to perform many invocations of resource property requests to different services (or the same service) at once, without waiting for the response from one request before starting a second request. The asynchronous client stubs generated for each operation allow the client to do this. The example code below shows the implementation of the callback that gets called once the response from a resource property has been received for the CounterService.

 typedef struct { globus_cond_t cond; globus_mutex_t mutex; } counter_monitor; void
        get_rp_counter_value_callback( CounterService_client_handle_t handle, void * user_args,
        globus_result_t result, const wsrp_GetResourcePropertyResponseType *
        GetResourcePropertyResponse, CounterPortType_GetResourceProperty_fault_t fault_type, const
        xsd_any * fault) { counter_monitor_t * monitor = (user_args); xsd_int * rp_value;
        if(GetResourcePropertyResponse->any.elements[0].any_info != (&Value_rp_info)) {
        /* error - expected Value as the first (and only) resource * property */ } rp_value =
        (xsd_int *)GetResourcePropertyResponse->any.elements[0].value;
        globus_mutex_lock(&monitor->mutex); monitor->value = *rp_value;
        monitor->done = 1; globus_cond_signal(&monitor->cond);
        globus_mutex_unlock(&monitor->mutex); } ... counter_monitor_t * monitor; monitor
        = globus_malloc(sizeof(counter_monitor_t)); /* check OOM */
        globus_cond_init(&monitor->cond, NULL);
        globus_mutex_init(&monitor->mutex, NULL); monitor->done = 0; monitor->value
        = 0; result = CounterPortType_GetResourceProperty_epr_register( client_handle,
        createCounterResponse->EndpointReference, &Value_rp_qname,
        get_rp_counter_value_callback, prop_monitor); if(result != GLOBUS_SUCCESS) { ... } /* do
        other processing */ globus_mutex_lock(&monitor->mutex); while(!monitor->done)
        { globus_cond_wait(&monitor->cond, &monitor->mutex); /* do other
        processing */ } globus_mutex_unlock(&monitor->mutex); 

This allows us to do other processing while the GetResourceProperty operation is invoked, and the response is returned. For something as simple as the CounterService, the wait for the callback to be called will most likely be short (unless there is network delay). For more complex services, the delay may be longer, and the client may want to perform other processing instead of just waiting.