1 /*
2 * Portions of this file Copyright 1999-2005 University of Chicago
3 * Portions of this file Copyright 1999-2005 The University of Southern California.
4 *
5 * This file or a portion of this file is licensed under the
6 * terms of the Globus Toolkit Public License, found at
7 * http://www.globus.org/toolkit/download/license.html.
8 * If you redistribute this file, with or without
9 * modifications, you must include this notice in the file.
10 */
11
12 #include "globus_common.h"
13 #include "globus_wsrf_resource.h"
14 #include "globus_service_engine.h"
15 #include "globus_service_registry.h"
16 #include "globus_wsrf_core_tools.h"
17 #include "wsnt_NotifyType.h"
18 #include "globus_i_notification_consumer.h"
19 #include "NotificationConsumerService.h"
20 #include "NotificationConsumerService_client.h"
21
22 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
23 /* Prototypes */
24 static
25 int
26 globus_l_notification_consumer_activate(void);
27
28 static
29 int
30 globus_l_notification_consumer_deactivate(void);
31
32 static
33 globus_result_t
34 globus_l_notification_create_resource_id(
35 xsd_any * * property,
36 char * resource_id);
37
38 /* Local Variables */
39 globus_mutex_t globus_i_notification_lock;
40 globus_cond_t globus_i_notification_cond;
41
42 globus_module_descriptor_t globus_i_notification_consumer_module =
43 {
44 "globus_notification_consumer",
45 globus_l_notification_consumer_activate,
46 globus_l_notification_consumer_deactivate
47 };
48 #endif /* GLOBUS_DONT_DOCUMENT_INTERNAL */
49
50 /* Client Helper API */
51 /**
52 * Create a NotificationConsumerService resource.
53 * @ingroup notification_consumer
54 *
55 * Create a notification consumer resource, which binds an resource endpoint
56 * to a user-defined callback. The @a consumer_reference passed to this
57 * function will be modified to contain an EPR to this resource which can
58 * be used as the ConsumerReference element in a Subscribe operation call
59 * when using the client stubs for a service which implements the
60 * NotificationProducer API.
61 *
62 * @param consumer_reference
63 * EPR to be populated to point to a new NotificationConsumer service
64 * resource instance.
65 * @param engine
66 * Service engine which will be used to process requests for this new
67 * new service.
68 * @param callback
69 * Pointer to the application callback to be called when a notification
70 * message is received for this resouce.
71 * @param callback_arg
72 * Application-specific parameter to the callback function.
73 *
74 * @retval GLOBUS_SUCCESS
75 * Consumer resource created successfully.
76 * @retval GLOBUS_NOTIFICATION_CONSUMER_ERROR_TYPE_NULL_PARAM
77 * Null parameter passed to this function.
78 * @retval GLOBUS_NOTIFICATION_CONSUMER_ERROR_TYPE_UNABLE_TO_CREATE_CONSUMER
79 * Unable to create consumer. Underlying cause will be chained to this
80 * error, but is typically an out-of-memory situation.
81 */
82 extern
83 globus_result_t
84 globus_notification_create_consumer(
85 wsa_EndpointReferenceType * consumer_reference,
86 globus_service_engine_t engine,
87 globus_notification_consumer_func_t callback,
88 void * callback_arg)
89 2 {
90 globus_result_t result;
91 globus_uuid_t resource_uuid;
92 globus_resource_t resource;
93 globus_i_notification_consumer_t * consumer;
94 xsd_any * resource_reference;
95
96 2 if (consumer_reference == NULL || callback == NULL)
97 {
98 0 result = GLOBUS_NOTIFICATION_CONSUMER_ERROR_NULL_PARAM(NULL);
99
100 0 goto out;
101 }
102
103 2 result = globus_uuid_create(&resource_uuid);
104 2 if (result != GLOBUS_SUCCESS)
105 {
106 0 result = GLOBUS_NOTIFICATION_CONSUMER_ERROR_UNABLE_TO_CREATE_CONSUMER(
107 globus_error_get(result));
108
109 0 goto out;
110 }
111
112 /* Create a resource which will represent this consumer. We'll associate
113 * the callback/arg with this resource
114 */
115 2 result = globus_resource_create(resource_uuid.text, &resource);
116 2 if (result != GLOBUS_SUCCESS)
117 {
118 0 result = GLOBUS_NOTIFICATION_CONSUMER_ERROR_UNABLE_TO_CREATE_CONSUMER(
119 globus_error_get(result));
120 0 goto out;
121 }
122
123 2 consumer = globus_libc_malloc(sizeof(globus_i_notification_consumer_t));
124
125 2 if (consumer == NULL)
126 {
127 0 result = GLOBUS_NOTIFICATION_CONSUMER_ERROR_UNABLE_TO_CREATE_CONSUMER(
128 globus_error_get(result));
129
130 0 goto destroy_resource_out;
131 }
132
133 2 consumer->callback = callback;
134 2 consumer->arg = callback_arg;
135 2 consumer->state = CONSUMER_OK;
136
137 2 result = globus_resource_set_resource_specific(
138 resource,
139 consumer,
140 globus_libc_free);
141
142 2 if (result != GLOBUS_SUCCESS)
143 {
144 0 result = GLOBUS_NOTIFICATION_CONSUMER_ERROR_UNABLE_TO_CREATE_CONSUMER(
145 globus_error_get(result));
146
147 0 goto free_consumer_out;
148 }
149
150 2 result = globus_l_notification_create_resource_id(
151 &resource_reference,
152 resource_uuid.text);
153
154 2 if (result != GLOBUS_SUCCESS)
155 {
156 0 result = GLOBUS_NOTIFICATION_CONSUMER_ERROR_UNABLE_TO_CREATE_CONSUMER(
157 globus_error_get(result));
158
159 0 goto destroy_resource_out;
160 }
161
162 2 result = globus_wsrf_core_create_endpoint_reference(
163 engine,
164 NOTIFICATIONCONSUMERSERVICE_BASE_PATH,
165 &resource_reference,
166 consumer_reference);
167
168 2 if (result != GLOBUS_SUCCESS)
169 {
170 0 result = GLOBUS_NOTIFICATION_CONSUMER_ERROR_UNABLE_TO_CREATE_CONSUMER(
171 globus_error_get(result));
172
173 0 goto destroy_resource_out;
174 }
175
176 2 return result;
177
178 0 free_consumer_out:
179 0 globus_libc_free(consumer);
180 0 destroy_resource_out:
181 0 globus_resource_destroy(resource);
182 0 out:
183 0 return result;
184 }
185 /* globus_notification_create_consumer() */
186
187 /**
188 * Destroy a consumer resource.
189 * @ingroup notification_consumer
190 *
191 * The resource associated with the EPR passed to this function will be
192 * destroyed. After this function returns, the callback associated with this
193 * resource will no longer be called.
194 *
195 * @param consumer_reference
196 * EPR of the resource to destroy.
197 *
198 * @retval GLOBUS_SUCCESS
199 * Consumer resource destroyed successfully.
200 * @retval GLOBUS_NOTIFICATION_CONSUMER_ERROR_TYPE_NULL_PARAM
201 * Null parameter passed to this function.
202 * @retval GLOBUS_NOTIFICATION_CONSUMER_ERROR_TYPE_UNKNOWN_RESOURCE
203 * The EPR does not refer to a valid resource.
204 */
205 extern
206 globus_result_t
207 globus_notification_destroy_consumer(
208 wsa_EndpointReferenceType * consumer_reference)
209 1 {
210 globus_result_t result;
211 globus_resource_t resource;
212 globus_i_notification_consumer_t * consumer;
213 1 globus_bool_t finish_it = GLOBUS_FALSE;
214
215 1 if (consumer_reference == NULL)
216 {
217 0 result = GLOBUS_NOTIFICATION_CONSUMER_ERROR_NULL_PARAM(NULL);
218
219 0 goto out;
220 }
221
222 1 globus_mutex_lock(&globus_i_notification_lock);
223
224 1 result = globus_wsrf_core_get_resource_from_epr(
225 consumer_reference,
226 &resource);
227
228 1 if (result != GLOBUS_SUCCESS || resource == NULL)
229 {
230 0 result = GLOBUS_NOTIFICATION_CONSUMER_ERROR_UNKNOWN_RESOURCE(
231 result ? globus_error_get(result) : NULL);
232
233 0 goto unlock_out;
234 }
235
236 1 result = globus_resource_get_resource_specific(
237 resource,
238 (void **)&consumer);
239
240 1 if (result != GLOBUS_SUCCESS || consumer == NULL)
241 {
242 0 result = GLOBUS_NOTIFICATION_CONSUMER_ERROR_UNKNOWN_RESOURCE(
243 result ? globus_error_get(result) : NULL);
244
245 0 goto finish_out;
246 }
247
248 2 while (consumer->state != CONSUMER_DESTROYED)
249 {
250 1 switch (consumer->state)
251 {
252 case CONSUMER_OK:
253 1 consumer->state = CONSUMER_DESTROYED;
254 1 globus_cond_broadcast(&globus_i_notification_cond);
255 1 finish_it = GLOBUS_TRUE;
256 1 break;
257
258 case CONSUMER_ACTIVE:
259 0 finish_it = GLOBUS_TRUE;
260 0 consumer->state = CONSUMER_ACTIVE_DESTROY_CALLED;
261 /* FALLSTHROUGH */
262 case CONSUMER_ACTIVE_DESTROY_CALLED:
263 0 globus_cond_wait(
264 &globus_i_notification_cond,
265 &globus_i_notification_lock);
266 break;
267
268 case CONSUMER_DESTROYED:
269 break;
270 }
271 }
272
273 1 finish_out:
274
275 1 if (finish_it)
276 {
277 /* Destroy resource---consumer is freed by the destroy call */
278 1 result = globus_resource_finish_and_destroy(resource);
279 }
280 else
281 {
282 /* Free reference from this function call */
283 0 result = globus_resource_finish(resource);
284 }
285
286 1 unlock_out:
287 1 globus_mutex_unlock(&globus_i_notification_lock);
288 1 out:
289 1 return result;
290 }
291 /* globus_notification_destroy_consumer() */
292
293 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
294 static
295 int
296 globus_l_notification_consumer_activate(void)
297 4 {
298 4 globus_module_activate(GLOBUS_COMMON_MODULE);
299 4 globus_module_activate(GLOBUS_SERVICE_ENGINE_MODULE);
300 4 globus_module_activate(GLOBUS_WSRF_RESOURCE_MODULE);
301 4 globus_module_activate(NOTIFICATIONCONSUMERSERVICE_MODULE);
302
303 4 globus_mutex_init(&globus_i_notification_lock, NULL);
304 4 globus_cond_init(&globus_i_notification_cond, NULL);
305
306 4 return GLOBUS_SUCCESS;
307 }
308 /* globus_l_notification_consumer_activate() */
309
310 static
311 int
312 globus_l_notification_consumer_deactivate(void)
313 3 {
314 3 globus_cond_destroy(&globus_i_notification_cond);
315 3 globus_mutex_destroy(&globus_i_notification_lock);
316
317 3 globus_module_deactivate(NOTIFICATIONCONSUMERSERVICE_MODULE);
318 3 globus_module_deactivate(GLOBUS_WSRF_RESOURCE_MODULE);
319 3 globus_module_deactivate(GLOBUS_SERVICE_ENGINE_MODULE);
320 3 globus_module_deactivate(GLOBUS_COMMON_MODULE);
321
322 3 return 0;
323 }
324 /* globus_l_notification_consumer_deactivate() */
325
326 /**
327 * Wrap the resource ID string in an XML any element with the QName
328 * http://www.ibm.com/xmlns/stdwip/web-services/WS-BaseNotification#ResourceId
329 *
330 * @param property
331 * Pointer to a xsd_any to allocate and populate.
332 * @param resource_id
333 * String to be used as the ResourceID
334 */
335 static
336 globus_result_t
337 globus_l_notification_create_resource_id(
338 xsd_any * * property,
339 char * resource_id)
340 2 {
341 xsd_string * val;
342 2 xsd_any_init(property);
343
344 2 (*property)->registry = NULL;
345 2 (*property)->any_info = &xsd_string_info;
346 2 (*property)->element = malloc(sizeof(xsd_QName));
347 2 (*property)->element->Namespace =
348 globus_libc_strdup(NOTIFICATION_NS);
349 2 (*property)->element->local = globus_libc_strdup("ResourceID");
350 2 val = (xsd_string *)malloc(sizeof(xsd_string));
351 2 *val = globus_libc_strdup(resource_id);
352 2 (*property)->value = val;
353
354 2 return GLOBUS_SUCCESS;
355 }
356 /* globus_l_notification_create_resource_id() */