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