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_i_wsrf_service_group.h"
18 #include "ServiceGroupEntryService.h"
19
20 static
21 globus_result_t
22 globus_l_service_group_uri_to_service_path(
23     const wsa_AttributedURI *           service_group_entry_uri,
24     char **                             service_path);
25
26 /**
27  * Create new service group state for a resource.
28  * @ingroup wssg
29  *
30  * Creates new service group state for a resouce named by the @a
31  * service_group_epr parameter. The service group will initially be empty.
32  * Other calls from this API may be used manage this service group.
33  *
34  * @param service_group_epr
35  *     EPR naming the service group. This EPR will be used as the key for
36  *     all service group operations.
37  * @param membership_content_rule
38  *     A rule for determining what services will be allowed into this service
39  *     group. Currently, the content element passed to
40  *     globus_service_group_add() must be of the same element type as one of
41  *     the values in the membership content rule.
42  * @param service_group_entry_uri
43  *     A URI path to be used for the service used to implement the service
44  *     group entries. Whenever a service is added to the group, a new resource
45  *     will be created and the providers handled by this service will be
46  *     initialized for the new resource. If this value is @a NULL, then the
47  *     ServiceGroupEntryService included in this package will be used.
48  * @param add_callback
49  *     Callback function which will be called when a service is added to the
50  *     group. The @a callback_arg parameter to this function will be passed
51  *     to the callback.
52  * @param remove_callback
53  *     Callback function which will be called when a service is removed from
54  *     the group. The @a callback_arg parameter to this function will be passed
55  *     to the callback.
56  * @param callback_arg
57  *     Application-specific argument to the @a add_callback and @a
58  *     remove_callback functions.
59  *
60  * @retval GLOBUS_SUCCESS
61  * @retval #GLOBUS_SERVICE_GROUP_ERROR_TYPE_NULL_PARAMETER
62  * @retval #GLOBUS_SERVICE_GROUP_ERROR_TYPE_OUT_OF_MEMORY
63  */
64 globus_result_t
65 globus_service_group_create(
66     const wsa_EndpointReferenceType *   service_group_epr,
67     const wssg_MembershipContentRuleType *
68                                         membership_content_rule,
69     const wsa_AttributedURI *           service_group_entry_uri,
70     globus_service_group_callback_t     add_callback,
71     globus_service_group_callback_t
72                                         remove_callback,
73     void *                              callback_arg)
74 21 {
75 21     globus_result_t                     result = GLOBUS_SUCCESS;
76 21     int                                 rc;
77 21     globus_wsrf_service_group_t         sg;
78 21     GlobusFuncName(globus_service_group_create);
79
80 21     GlobusServiceGroupDebugEnter();
81
82 21     if (service_group_epr == NULL || membership_content_rule == NULL)
83     {
84 2         result = GLOBUS_SERVICE_GROUP_NULL_PARAMETER();
85
86 2         goto out;
87     }
88
89 19     sg = malloc(sizeof(globus_i_wsrf_service_group_t));
90
91 19     if (sg == NULL)
92     {
93 0         goto out;
94     }
95
96 19     sg->add_callback = add_callback;
97 19     sg->remove_callback = remove_callback;
98 19     sg->callback_arg = callback_arg;
99
100 19     rc = globus_hashtable_init(
101                 &sg->entries,
102                 5,
103                 globus_hashtable_string_hash,
104                 globus_hashtable_string_keyeq);
105 19     if (rc != 0)
106     {
107 0         result = GLOBUS_SERVICE_GROUP_OUT_OF_MEMORY();
108
109 0         goto free_sg_out;
110     }
111
112 19     result = wsa_EndpointReferenceType_copy_contents(
113             &sg->service_group_epr,
114             service_group_epr);
115
116 19     if (result != GLOBUS_SUCCESS)
117     {
118 0         result = GLOBUS_SERVICE_GROUP_OUT_OF_MEMORY();
119
120 0         goto destroy_entries_out;
121     }
122
123     /* If the service_group_entry URI is undefined, we will use the
124      * path to the ServiceGroupEntry service (from this source package)
125      */
126 19     if (service_group_entry_uri == NULL)
127     {
128 19         char *                          tmp;
129
130 19         result = wsa_AttributedURI_copy_contents(
131                 &sg->service_group_entry_uri,
132                 &service_group_epr->Address);
133
134 19         if (result != GLOBUS_SUCCESS)
135         {
136 0             result = GLOBUS_SERVICE_GROUP_OUT_OF_MEMORY();
137
138 0             goto destroy_service_group_epr_out;
139         }
140
141 19         tmp = realloc(
142                 sg->service_group_entry_uri.base_value,
143                 strlen(sg->service_group_entry_uri.base_value) +
144                 strlen(SERVICEGROUPENTRYSERVICE_BASE_PATH) + 2);
145
146 19         if (tmp == NULL)
147         {
148 0             result = GLOBUS_SERVICE_GROUP_OUT_OF_MEMORY();
149
150 0             goto destroy_service_group_entry_uri_out;
151         }
152
153 19         sg->service_group_entry_uri.base_value = tmp;
154
155 19         tmp = strstr(tmp, "://");
156
157 19         if (tmp == NULL)
158         {
159 0             result = GLOBUS_SERVICE_GROUP_OUT_OF_MEMORY();
160
161 0             goto destroy_service_group_entry_uri_out;
162         }
163
164 19         tmp += 3;
165
166 325         while (*tmp && *tmp != '/')
167         {
168 306             tmp++;
169         }
170
171 19         if (*tmp == '\0')
172         {
173 0             result = GLOBUS_SERVICE_GROUP_OUT_OF_MEMORY();
174
175 0             goto destroy_service_group_entry_uri_out;
176         }
177
178 19         strcpy(tmp+1, SERVICEGROUPENTRYSERVICE_BASE_PATH);
179     }
180     else
181     {
182 0         result = wsa_AttributedURI_copy_contents(
183                 &sg->service_group_entry_uri,
184                 service_group_entry_uri);
185
186 0         if (result != GLOBUS_SUCCESS)
187         {
188 0             result = GLOBUS_SERVICE_GROUP_OUT_OF_MEMORY();
189
190 0             goto destroy_service_group_epr_out;
191         }
192     }
193
194 19     result = globus_wsrf_core_get_resource_id_from_epr(
195             &sg->service_group_epr,
196             &sg->resource_id);
197
198 19     if (result != GLOBUS_SUCCESS)
199     {
200 0         result = GLOBUS_SERVICE_GROUP_OUT_OF_MEMORY();
201
202 0         goto destroy_service_group_entry_uri_out;
203     }
204
205 19     rc = globus_mutex_init(&sg->lock, NULL);
206 19     if (rc != GLOBUS_SUCCESS)
207     {
208 0         result = GLOBUS_SERVICE_GROUP_OUT_OF_MEMORY();
209
210 0         goto destroy_resource_id_out;
211     }
212
213 19     result = wssg_MembershipContentRuleType_copy(
214             &sg->membership_content_rule,
215             membership_content_rule);
216 19     if (result != GLOBUS_SUCCESS)
217     {
218 0         result = GLOBUS_SERVICE_GROUP_OUT_OF_MEMORY();
219
220 0         goto destroy_mutex_out;
221     }
222
223 19     result = globus_l_service_group_uri_to_service_path(
224         &sg->service_group_entry_uri,
225         &sg->service_group_entry_path);
226
227 19     if (result != GLOBUS_SUCCESS)
228     {
229 0         goto destroy_membership_content_rule;
230     }
231
232 19     GlobusServiceGroupGlobalLock();
233 19     rc = globus_hashtable_insert(
234                 &globus_i_service_groups,
235                 sg->resource_id,
236                 sg);
237 19     GlobusServiceGroupGlobalUnlock();
238 19     if (rc != GLOBUS_SUCCESS)
239     {
240 0         result = GLOBUS_SERVICE_GROUP_OUT_OF_MEMORY();
241
242 0         goto destroy_service_group_entry_path_out;
243     }
244
245 19     return result;
246
247 destroy_service_group_entry_path_out:
248 0     free(sg->service_group_entry_path);
249 destroy_membership_content_rule:
250 0     wssg_MembershipContentRuleType_destroy(sg->membership_content_rule);
251 destroy_mutex_out:
252 0     globus_mutex_destroy(&sg->lock);
253 destroy_resource_id_out:
254 0     free(sg->resource_id);
255 destroy_service_group_entry_uri_out:
256 0     wsa_AttributedURI_destroy_contents(&sg->service_group_entry_uri);
257 destroy_service_group_epr_out:
258 0     wsa_EndpointReferenceType_destroy_contents(&sg->service_group_epr);
259 destroy_entries_out:
260 0     globus_hashtable_destroy(&sg->entries);
261 free_sg_out:
262 0     free(sg);
263 out:
264 2     GlobusServiceGroupDebugExit();
265 2     return result;
266 }
267 /* globus_service_group_create() */
268
269 static
270 globus_result_t
271 globus_l_service_group_uri_to_service_path(
272     const wsa_AttributedURI *           service_group_entry_uri,
273     char **                             service_path)
274 19 {
275 19     const char *                        tmp;
276 19     globus_url_t                        url;
277 19     char *                              path;
278 19     int                                 rc;
279 19     globus_result_t                     result = GLOBUS_SUCCESS;
280 19     GlobusFuncName(globus_l_service_group_uri_to_service_path);
281
282 19     GlobusServiceGroupDebugEnter();
283 19     rc = globus_url_parse(service_group_entry_uri->base_value, &url);
284
285 19     if (rc != GLOBUS_SUCCESS)
286     {
287 0         return GLOBUS_SERVICE_GROUP_OUT_OF_MEMORY();
288     }
289
290 19     tmp = url.url_path;
291 38     while(*tmp == '/')
292     {
293 19         tmp++;
294     }
295
296 19     path = globus_common_create_string(
297             "%s/%s",
298             GLOBUS_SERVICE_ENGINE_MODULE_PATH_PREFIX,
299             tmp);
300
301 19     globus_url_destroy(&url);
302
303 19     *service_path = path;
304
305 19     GlobusServiceGroupDebugExit();
306
307 19     return result;
308 }