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_soap_message.h"
18 #include "globus_wsrf_resource.h"
19 #include "globus_service_engine.h"
20 #include "globus_operation_provider.h"
21 #include "globus_wsrf_core_tools.h"
22 #include "globus_wsrf_service_group.h"
23 #include "globus_notification_producer.h"
24
25 #include "wssg_Entry.h"
26 #include "wssg_Content.h"
27 #include "wssg_EntryType.h"
28
29 #include "wssg_MembershipContentRuleType.h"
30 #include "wssg_MembershipContentRule.h"
31 #include "wssg_ServiceGroupModificationNotificationType.h"
32 #include "wssg_EntryAdditionNotification.h"
33 #include "wssg_EntryRemovalNotification.h"
34 #include "wsa_EndpointReferenceType.h"
35 #include "wsnt_TopicExpressionType.h"
36
37 #include "version.h"
38
39
40 /**
41  * @defgroup wssg_ServiceGroup_provider ServiceGroup Provider
42  *
43  * <h2>Provider Usage Overview</h2>
44  * This operation provider implements the ServiceGroup portType
45  * defined in
46  * http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ServiceGroup-1.2-draft-02.pdf
47  * 
48  * This portType consists of resource properties wssg:EntryURI and
49  * wssg:MembershipContentRule.
50  *
51  * This provider is located in the
52  * @b globus_wssg_ServiceGroup_provider extension. After this
53  * extension is activated, the provider may be associated with a service by
54  * adding the provider for 
55  {http://www.globus.org/docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ServiceGroup-1.2-draft-01.wsdl}ServiceGroup to the service.
56  */
57
58 /* Prototypes */
59 static
60 globus_result_t
61 wssg_ServiceGroup_init_resource(
62     const struct wsa_EndpointReferenceType_s *epr);
63
64 static
65 void
66 wssg_ServiceGroup_get_property(
67     void *                              arg,
68     const xsd_QName *                   qname,
69     void **                             property);
70
71 static
72 globus_bool_t
73 wssg_ServiceGroup_set_property(
74     void *                              arg,
75     const xsd_QName *                   qname,
76     void *                              property);
77
78 static
79 void
80 wssg_l_entry_add_callback(
81     void *                              arg,
82     const wssg_EntryType *              entry);
83
84 static
85 void
86 wssg_l_entry_remove_callback(
87     void *                              arg,
88     const wssg_EntryType *              entry);
89
90 static
91 int
92 wssg_l_ServiceGroup_activate(void);
93
94 static
95 int
96 wssg_l_ServiceGroup_deactivate(void);
97
98 /* Local Variables */
99 static xsd_QName wssg_ServiceGroup_qname =
100 {
101     "http://www.globus.org/docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ServiceGroup-1.2-draft-01.wsdl",
102     "ServiceGroup"
103 };
104
105 static
106 wsnt_TopicExpressionType                wssg_EntryAdditionTopic;
107
108 static
109 wsnt_TopicExpressionType                wssg_EntryRemovalTopic;
110
111 static
112 globus_operation_provider_descriptor_t
113 wssg_ServiceGroup_descriptor =
114 {
115     &wssg_ServiceGroup_qname,
116     "ServiceGroup",
117     NULL,
118     wssg_ServiceGroup_init_resource
119 };
120
121 GlobusExtensionDefineModule(globus_wssg_ServiceGroup_provider) =
122 {
123     "globus_wssg_ServiceGroup_provider",
124     wssg_l_ServiceGroup_activate,
125     wssg_l_ServiceGroup_deactivate,
126     NULL,
127     NULL,
128     &local_version
129 };
130
131
132 /**
133  * Initialize the ServiceGroup parts of the resource. This will use the
134  * globus_wsrf_service_group API to create state used to handle service
135  * group entry management, and then create some ResourceProperties which
136  * are expected by a service group implemtation.
137  *
138  * In order to set up the service group, we need to know 2 WSRF
139  * resource-specific pieces of information. One is the
140  * wssg:MembershipContentRule (which governs membership into the group) and
141  * another is the URI of the service which implements the
142  * wssg:ServiceGroupEntry functionality. We assume these are communicated
143  * through two resource properties: wssg:MembershipContentRule (an official
144  * part of the ServiceGroup resource definition), and wssg:ServiceGroupEntryURI
145  * (something added for this implementation--it's value is the URI of the
146  * service which will implement the ServiceGroupEntry functionality). If the
147  * latter is not defined, we will construct one using the default implementation
148  * of service group entries, but the former is required if the provider is
149  * to work. 
150  */
151 static
152 globus_result_t
153 wssg_ServiceGroup_init_resource(
154     const struct wsa_EndpointReferenceType_s *
155                                         epr)
156 4 {
157 4     globus_result_t                     result;
158 4     char *                              resource_id;
159 4     globus_resource_t                   resource;
160 4     wssg_MembershipContentRuleType *    membership_content_rule;
161 4     wsa_AttributedURI *                 service_group_entry_uri = NULL;
162 4     xsd_QName                           wssg_ServiceGroupEntryURI = 
163     {
164         "http://www.globus.org/docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ServiceGroup-1.2-draft-01.wsdl",
165         "ServiceGroupEntryURI"
166 4     };
167 4     wsa_EndpointReferenceType *         epr_copy;
168
169 4     result = globus_wsrf_core_get_resource_id_from_epr(
170             epr,
171             &resource_id);
172
173 4     if (result != GLOBUS_SUCCESS)
174     {
175 0         goto out;
176     }
177 4     result = globus_resource_find(
178             resource_id,
179             &resource);
180 4     if (result != GLOBUS_SUCCESS)
181     {
182 0         goto free_resource_id_out;
183     }
184 4     result = globus_notification_producer_create(
185             resource_id,
186             NULL,
187             NULL);
188
189 4     if (result != GLOBUS_SUCCESS)
190     {
191 0         goto finish_out;
192     }
193
194 4     result = globus_resource_get_property(
195             resource,
196             &wssg_MembershipContentRule_qname,
197             (void **) &membership_content_rule,
198             NULL);
199
200 4     if (result != GLOBUS_SUCCESS)
201     {
202 0         goto finish_out;
203     }
204
205 4     result = globus_resource_get_property(
206             resource,
207             &wssg_ServiceGroupEntryURI,
208             (void **) &service_group_entry_uri,
209             NULL);
210
211     /* It's ok if this property isn't present---the service_group module
212      * has a reasonable default service_group_entry_uri value.
213      */
214 4     if (result != GLOBUS_SUCCESS &&
215             !globus_error_match(globus_error_peek(result),
216                     GLOBUS_WSRF_RESOURCE_MODULE,
217                     GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY))
218     {
219 0         goto finish_out;
220     }
221
222 4     result = wsa_EndpointReferenceType_copy(
223             &epr_copy,
224             epr);
225
226 4     if (result != GLOBUS_SUCCESS)
227     {
228 0         goto finish_out;
229     }
230
231 4     result = globus_service_group_create(
232             epr,
233             membership_content_rule,
234             service_group_entry_uri,
235             wssg_l_entry_add_callback,
236             wssg_l_entry_remove_callback,
237             epr_copy);
238
239 4     if (result != GLOBUS_SUCCESS)
240     {
241 0         goto free_epr_copy_out;
242     }
243
244 4     result = globus_notification_producer_topic_create(
245             resource_id,
246             &wssg_EntryAdditionTopic);
247
248 4     if (result != GLOBUS_SUCCESS)
249     {
250 0         goto destroy_service_group_out;
251     }
252 4     result = globus_notification_producer_topic_create(
253             resource_id,
254             &wssg_EntryRemovalTopic);
255
256 4     if (result != GLOBUS_SUCCESS)
257     {
258 0         goto destroy_service_group_out;
259     }
260
261 4     result = globus_resource_create_property_callback(
262             resource,
263             &wssg_Entry_qname,
264             &wssg_EntryType_array_info,
265             wssg_ServiceGroup_get_property,
266             wssg_ServiceGroup_set_property,
267             epr_copy);
268
269 4     if (result != GLOBUS_SUCCESS)
270     {
271 destroy_service_group_out:
272 0         globus_service_group_destroy(epr);
273 free_epr_copy_out:
274 0         wsa_EndpointReferenceType_destroy(epr_copy);
275     }
276 finish_out:
277 4     globus_resource_finish(resource);
278 free_resource_id_out:
279 4     free(resource_id);
280 out:
281 4     return result;
282 }
283 /* wssg_ServiceGroup_init_resource() */
284
285 static
286 void
287 wssg_ServiceGroup_get_property(
288     void *                              arg,
289     const xsd_QName *                   qname,
290     void **                             property)
291 4 {
292 4     globus_resource_t                   resource;
293 4     globus_result_t                     result;
294 4     wssg_EntryType_array *              entries;
295
296 4     *property = NULL;
297
298 4     result = globus_wsrf_core_get_resource_from_epr(
299             arg,
300             &resource);
301 4     if (result != GLOBUS_SUCCESS)
302     {
303 0         goto out;
304     }
305 4     if (!xsd_QName_keyeq((void *) qname, &wssg_Entry_qname))
306     {
307 0         goto finish_out;
308     }
309
310 4     result = wssg_EntryType_array_init(&entries);
311 4     if (result != GLOBUS_SUCCESS)
312     {
313 0         goto finish_out;
314     }
315
316 4     result = globus_service_group_get_entries(
317         arg,
318         entries);
319
320 4     if (result != GLOBUS_SUCCESS)
321     {
322 0         goto free_entries_out;
323     }
324
325 4     *property = entries;
326
327 free_entries_out:
328 4     if (result != GLOBUS_SUCCESS)
329     {
330 0         wssg_EntryType_array_destroy(entries);
331     }
332 finish_out:
333 4     globus_resource_finish(resource);
334 out:
335 4     return;
336 }
337 /* wssg_ServiceGroup_get_property() */
338
339 static
340 globus_bool_t
341 wssg_ServiceGroup_set_property(
342     void *                              arg,
343     const xsd_QName *                   qname,
344     void *                              property)
345 0 {
346     /* The properties defined here are not settable by other code */
347 0     return GLOBUS_FALSE;
348 }
349 /* wssg_ServiceGroup_set_property() */
350
351
352 static
353 void
354 wssg_l_entry_add_callback(
355     void *                              arg,
356     const wssg_EntryType *              entry)
357 3 {
358 3     char *                              resource_id;
359 3     globus_result_t                     result;
360 3     xsd_anyType *                       message;
361     wssg_ServiceGroupModificationNotificationType
362 3                                         notification;
363 3     globus_resource_t                   entry_resource;
364
365 3     result = globus_wsrf_core_get_resource_id_from_epr(
366             arg,
367             &resource_id);
368
369 3     if (result != GLOBUS_SUCCESS)
370     {
371 0         goto out;
372     }
373
374 3     result = xsd_anyType_init(&message);
375 3     if (result != GLOBUS_SUCCESS)
376     {
377 0         goto free_resource_id_out;
378     }
379
380 3     message->any_info = &wssg_EntryAdditionNotification_info;
381
382 3     result = wssg_ServiceGroupModificationNotificationType_init_contents(
383             &notification);
384 3     if (result != GLOBUS_SUCCESS)
385     {
386 0         goto destroy_message_out;
387     }
388
389 3     notification.ServiceGroupEntryEPR = entry->ServiceGroupEntryEPR;
390 3     notification.MemberServiceEPR = entry->MemberServiceEPR;
391
392 3     result = globus_wsrf_core_get_resource_from_epr(
393             entry->ServiceGroupEntryEPR,
394             &entry_resource);
395 3     if (result != GLOBUS_SUCCESS)
396     {
397 0         goto destroy_message_out;
398     }
399 3     result = globus_resource_get_property(
400             entry_resource,
401             &wssg_Content_qname,
402             (void **) &notification.Content,
403             NULL);
404 3     if (result != GLOBUS_SUCCESS)
405     {
406 0         goto finish_entry_resource_out;
407     }
408 3     message->value = &notification;
409
410 3     result = globus_notification_producer_topic_changed(
411             resource_id,
412             &wssg_EntryAdditionTopic,
413             message,
414             NULL,
415             NULL);
416
417 3     message->value = NULL;
418
419 finish_entry_resource_out:
420 3     globus_resource_finish(entry_resource);
421 destroy_message_out:
422 3     xsd_anyType_destroy(message);
423 free_resource_id_out:
424 3     free(resource_id);
425 out:
426 3     return;
427 }
428 /* wssg_l_entry_add_callback() */
429
430 static
431 void
432 wssg_l_entry_remove_callback(
433     void *                              arg,
434     const wssg_EntryType *              entry)
435 0 {
436 0     char *                              resource_id;
437 0     globus_result_t                     result;
438 0     xsd_anyType *                       message;
439     wssg_ServiceGroupModificationNotificationType
440 0                                         notification;
441 0     globus_resource_t                   entry_resource;
442
443 0     result = globus_wsrf_core_get_resource_id_from_epr(
444             arg,
445             &resource_id);
446
447 0     if (result != GLOBUS_SUCCESS)
448     {
449 0         goto out;
450     }
451
452 0     result = xsd_anyType_init(&message);
453 0     if (result != GLOBUS_SUCCESS)
454     {
455 0         goto free_resource_id_out;
456     }
457
458 0     message->any_info = &wssg_EntryRemovalNotification_info;
459
460 0     result = wssg_ServiceGroupModificationNotificationType_init_contents(
461             &notification);
462 0     if (result != GLOBUS_SUCCESS)
463     {
464 0         goto destroy_message_out;
465     }
466
467 0     notification.ServiceGroupEntryEPR = entry->ServiceGroupEntryEPR;
468 0     notification.MemberServiceEPR = entry->MemberServiceEPR;
469
470 0     result = globus_wsrf_core_get_resource_from_epr(
471             entry->ServiceGroupEntryEPR,
472             &entry_resource);
473 0     if (result != GLOBUS_SUCCESS)
474     {
475 0         goto destroy_message_out;
476     }
477 0     result = globus_resource_get_property(
478             entry_resource,
479             &wssg_Content_qname,
480             (void **) &notification.Content,
481             NULL);
482 0     if (result != GLOBUS_SUCCESS)
483     {
484 0         goto finish_entry_resource_out;
485     }
486 0     message->value = &notification;
487
488 0     result = globus_notification_producer_topic_changed(
489             resource_id,
490             &wssg_EntryRemovalTopic,
491             message,
492             NULL,
493             NULL);
494
495 0     message->value = NULL;
496
497 finish_entry_resource_out:
498 0     globus_resource_finish(entry_resource);
499 destroy_message_out:
500 0     xsd_anyType_destroy(message);
501 free_resource_id_out:
502 0     free(resource_id);
503 out:
504 0     return;
505 }
506
507 #define WSNT_NS \
508 "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ServiceGroup-1.2-draft-01.xsd"
509
510 static
511 int
512 wssg_l_ServiceGroup_activate(void)
513 25 {
514 25     int                                 res = 0;
515     static
516     xsd_QName wssg_EntryAdditionTopic_qname =
517     {
518         WSNT_NS,
519         "EntryAdditionNotification"
520 25     };
521
522     static
523     xsd_QName wssg_EntryRemovalTopic_qname =
524     {
525         WSNT_NS,
526         "EntryRemovalNotification"
527 25     };
528
529 25     GlobusFuncName(wssg_l_ServiceGroup_activate);
530     
531 25     res = globus_module_activate(GLOBUS_WSRF_SERVICE_GROUP_MODULE);
532 25     if (res != GLOBUS_SUCCESS)
533     {
534 0         goto out;
535     }
536
537 25     res = globus_module_activate(GLOBUS_NOTIFICATION_PRODUCER_MODULE);
538
539 25     if (res != GLOBUS_SUCCESS)
540     {
541 0         goto deactivate_service_group_out;
542     }
543 25     res = globus_notification_producer_set_simple_topic_expression_contents(
544             &wssg_EntryAdditionTopic,
545             &wssg_EntryAdditionTopic_qname);
546 25     if (res != GLOBUS_SUCCESS)
547     {
548 0         goto deactivate_notification_producer_out;
549     }
550 25     res = globus_notification_producer_set_simple_topic_expression_contents(
551             &wssg_EntryRemovalTopic,
552             &wssg_EntryRemovalTopic_qname);
553 25     if (res != GLOBUS_SUCCESS)
554     {
555 0         goto destroy_addition_topic;
556     }
557
558 25     res = globus_extension_registry_add(
559         GLOBUS_OPERATION_PROVIDER_REGISTRY,
560         &wssg_ServiceGroup_qname,
561         GlobusExtensionMyModule(globus_wssg_ServiceGroup_provider),
562         &wssg_ServiceGroup_descriptor);
563
564 25     if (res != GLOBUS_SUCCESS)
565     {
566 0     wsnt_TopicExpressionType_destroy_contents(&wssg_EntryRemovalTopic);
567 destroy_addition_topic:
568 0     wsnt_TopicExpressionType_destroy_contents(&wssg_EntryAdditionTopic);
569 deactivate_notification_producer_out:
570 0         globus_module_deactivate(GLOBUS_NOTIFICATION_PRODUCER_MODULE);
571 deactivate_service_group_out:
572 0         globus_module_deactivate(GLOBUS_WSRF_SERVICE_GROUP_MODULE);
573     }
574 out:
575 25     return res;
576 }
577 /* wssg_ServiceGroup_activate() */
578
579 static
580 int
581 wssg_l_ServiceGroup_deactivate(void)
582 21 {
583 21     GlobusFuncName(wssg_ServiceGroup_deactivate);
584
585 21     globus_extension_registry_remove(
586         GLOBUS_OPERATION_PROVIDER_REGISTRY,
587         &wssg_ServiceGroup_qname);
588
589 21     wsnt_TopicExpressionType_destroy_contents(&wssg_EntryAdditionTopic);
590 21     wsnt_TopicExpressionType_destroy_contents(&wssg_EntryRemovalTopic);
591 21     globus_module_deactivate(GLOBUS_NOTIFICATION_PRODUCER_MODULE);
592 21     globus_module_deactivate(GLOBUS_WSRF_SERVICE_GROUP_MODULE);
593
594 21     return 0;
595 }