1 /* $Id$
2 *
3 * Lasso - A free implementation of the Liberty Alliance specifications.
4 *
5 * Copyright (C) 2004-2007 Entr'ouvert
6 * http://lasso.entrouvert.org
7 *
8 * Authors: See AUTHORS file in top-level directory.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include <glib.h>
25 #include "registry-private.h"
26 #include "errors.h"
27 #include "utils.h"
28
29
30 /**
31 * SECTION:registry
32 * @short_description: Class to store a mapping of qualified names (QName) to other qualified names.
33 *
34 * A qualified name is a name or a string in the context of another name, or namespace.
35 * This object implement a function of a tuple (namespace, name, namespace) to a name. For the
36 * moment there is no need to enumerate all tuples (namespace, name) pair given a base pair, i.e. a
37 * function from tuple (namespace, name) to a list of tuples (namespace,name).
38 *
39 * We support two kinds of mapping:
40 * <itemizedlist>
41 * <listitem><para>you can give a direct mapping between two QName,</para></listitem>
42 * <listitem><para>or you can give a function that will manage mapping between one namespace and
43 * another one.</para></listitem>
44 * </itemizedlist>
45 *
46 * For internal use inside lasso we define the following namespaces:
47 * <itemizedlist>
48 * <listitem><para>#LASSO_LASSO_HREF and,</para></listitem>
49 * <listitem><para>#LASSO_PYTHON_HREF.</para></listitem>
50 * </itemizedlist>
51 *
52 * For functional mappings the mapping function must return constant strings created using
53 * g_intern_string() or using g_type_name().
54 */
55
56 typedef struct _LassoRegistryDirectMappingRecord LassoRegistryDirectMappingRecord;
57
58 struct _LassoRegistryDirectMappingRecord {
59 GQuark from_namespace;
60 GQuark from_name;
61 GQuark to_namespace;
62 GQuark to_name;
63 };
64
65 typedef struct _LassoRegistryFunctionalMappingRecord LassoRegistryFunctionalMappingRecord;
66
67 struct _LassoRegistryFunctionalMappingRecord {
68 GQuark from_namespace;
69 GQuark to_namespace;
70 LassoRegistryTranslationFunction translation_function;
71 };
72
73 static LassoRegistry *default_registry = NULL;
74
lasso_registry_get_default()75 static LassoRegistry *lasso_registry_get_default() {
76 if (default_registry == NULL) {
77 default_registry = lasso_registry_new();
78 }
79 return default_registry;
80 }
81
lasso_registry_default_shutdown()82 void lasso_registry_default_shutdown()
83 {
84 if (default_registry)
85 lasso_registry_destroy(default_registry);
86 default_registry = NULL;
87 }
88
89 /**
90 * lasso_registry_direct_mapping_equal:
91 * @record1: left record
92 * @record2: right record
93 *
94 * Tests if two #LassoRegistryDirectMappingRecord are equal.
95 *
96 * Return value: TRUE if all field of record1 are equal to record2.
97 */
lasso_registry_direct_mapping_equal(LassoRegistryDirectMappingRecord * record1,LassoRegistryDirectMappingRecord * record2)98 gboolean lasso_registry_direct_mapping_equal(LassoRegistryDirectMappingRecord *record1,
99 LassoRegistryDirectMappingRecord *record2)
100 {
101 return record1->from_namespace == record2->from_namespace
102 && record1->from_name == record2->from_name
103 && record1->to_namespace == record2->to_namespace;
104 }
105
106 /**
107 * lasso_registry_functional_mapping_equal:
108 * @record1: left record
109 * @record2: right record
110 *
111 * Tests if two #LassoRegistryFunctionalMappingRecord are equal, i.e. if they are functional
112 * mapping between the same namespace.
113 *
114 * Return value: TRUE if record1 is equal to record2
115 */
lasso_registry_functional_mapping_equal(LassoRegistryFunctionalMappingRecord * record1,LassoRegistryFunctionalMappingRecord * record2)116 gboolean lasso_registry_functional_mapping_equal(LassoRegistryFunctionalMappingRecord *record1,
117 LassoRegistryFunctionalMappingRecord *record2)
118 {
119 return record1->from_namespace == record2->from_namespace &&
120 record1->to_namespace == record2->to_namespace;
121 }
122
123 /**
124 * lasso_registry_direct_mapping_hash:
125 * @record: a #LassoRegistryDirectMappingRecord structure
126 *
127 * Return a hash value obtained from the three first fields of a #LassoRecordRegistry structure.
128 *
129 * Return value: an integer hash for the record.
130 */
lasso_registry_direct_mapping_hash(LassoRegistryDirectMappingRecord * record)131 guint lasso_registry_direct_mapping_hash(LassoRegistryDirectMappingRecord *record)
132 {
133 return g_direct_hash((gpointer)((ptrdiff_t)record->from_namespace
134 ^ (ptrdiff_t)record->from_name
135 ^ (ptrdiff_t)record->to_namespace));
136 }
137
138 /**
139 * lasso_registry_functional_mapping_hash:
140 * @record: a #LassoRegistryFunctionalMappingRecord structure
141 *
142 * Return a hash value obtained from the source and destination namespace of the mapping.
143 *
144 * Return value: an integer hash for the record.
145 */
lasso_registry_functional_mapping_hash(LassoRegistryFunctionalMappingRecord * record)146 guint lasso_registry_functional_mapping_hash(LassoRegistryFunctionalMappingRecord *record)
147 {
148 return g_direct_hash((gpointer)((ptrdiff_t)record->from_namespace
149 ^ (ptrdiff_t)record->to_namespace));
150 }
151
152 /**
153 * lasso_registry_new:
154 *
155 * Allocate a new #LassoRegistry structure and initialize its fields.
156 *
157 * Return value: a newly allocated #LassoRegistry object.
158 */
lasso_registry_new()159 LassoRegistry *lasso_registry_new()
160 {
161 LassoRegistry *ret = g_new0(LassoRegistry, 1);
162
163 ret->direct_mapping = g_hash_table_new_full(
164 (GHashFunc) lasso_registry_direct_mapping_hash,
165 (GEqualFunc) lasso_registry_direct_mapping_equal,
166 NULL,
167 g_free);
168
169 ret->functional_mapping = g_hash_table_new_full(
170 (GHashFunc) lasso_registry_functional_mapping_hash,
171 (GEqualFunc) lasso_registry_functional_mapping_equal,
172 NULL,
173 g_free);
174
175 return ret;
176 }
177
178 /**
179 * lasso_registry_destroy:
180 * @registry: the #LassoRegistry object
181 *
182 * Destroy a #LassoRegistry.
183 */
lasso_registry_destroy(LassoRegistry * registry)184 void lasso_registry_destroy(LassoRegistry *registry)
185 {
186 g_return_if_fail(registry);
187
188 lasso_release_ghashtable(registry->direct_mapping);
189 lasso_release_ghashtable(registry->functional_mapping);
190 lasso_release(registry);
191 }
192
lasso_registry_get_translation_function(GHashTable * functional_mappings,GQuark from_ns_quark,GQuark to_ns_quark)193 static LassoRegistryTranslationFunction lasso_registry_get_translation_function(GHashTable *functional_mappings, GQuark from_ns_quark, GQuark to_ns_quark)
194 {
195 LassoRegistryFunctionalMappingRecord functional_mapping, *functional_mapping_found;
196 functional_mapping.from_namespace = from_ns_quark;
197 functional_mapping.to_namespace = to_ns_quark;
198 functional_mapping_found = g_hash_table_lookup(functional_mappings, &functional_mapping);
199
200 if (functional_mapping_found) {
201 return functional_mapping_found->translation_function;
202 }
203 return NULL;
204 }
205
lasso_registry_get_functional_mapping(GHashTable * functional_mappings,GQuark from_ns_namespace,const char * from_name,GQuark to_ns_namespace)206 static const char *lasso_registry_get_functional_mapping(GHashTable *functional_mappings,
207 GQuark from_ns_namespace, const char *from_name, GQuark to_ns_namespace)
208 {
209 LassoRegistryTranslationFunction translation_function;
210
211 translation_function = lasso_registry_get_translation_function(functional_mappings, from_ns_namespace, to_ns_namespace);
212 if (translation_function) {
213 return translation_function(g_quark_to_string(from_ns_namespace), from_name, g_quark_to_string(to_ns_namespace));
214 }
215 return NULL;
216 }
217
lasso_registry_get_direct_mapping(GHashTable * direct_mappings,GQuark from_ns_quark,const char * from_name,GQuark to_ns_quark)218 static const char *lasso_registry_get_direct_mapping(GHashTable *direct_mappings,
219 GQuark from_ns_quark, const char *from_name, GQuark to_ns_quark)
220 {
221 GQuark from_name_quark = g_quark_try_string(from_name);
222 LassoRegistryDirectMappingRecord record, *found;
223
224 if (from_name_quark == 0)
225 return NULL;
226
227 record.from_namespace = from_ns_quark;
228 record.from_name = from_name_quark;
229 record.to_namespace = to_ns_quark;
230
231 found = g_hash_table_lookup(direct_mappings, &record);
232
233 if (found) {
234 return g_quark_to_string(found->to_name);
235 }
236 return NULL;
237 }
238
239 /**
240 * lasso_regsitry_get_mapping:
241 *
242 * Retrieve the mapping of a QName into another namespace, i.e. to another
243 * QName. It first tries the functional mapping, then tries with the direct mapping.
244 *
245 * Return value: a constant string of NULL if no mapping exist.
246 */
lasso_registry_get_mapping(LassoRegistry * registry,const char * from_namespace,const char * from_name,const char * to_namespace)247 const char* lasso_registry_get_mapping(LassoRegistry *registry, const char *from_namespace,
248 const char *from_name, const char *to_namespace)
249 {
250 GQuark from_ns_quark, to_ns_quark;
251 const char *ret = NULL;
252
253 from_ns_quark = g_quark_try_string(from_namespace);
254 to_ns_quark = g_quark_try_string(to_namespace);
255
256 if (from_ns_quark == 0 || to_ns_quark == 0) {
257 return NULL;
258 }
259
260 ret = lasso_registry_get_functional_mapping(registry->functional_mapping, from_ns_quark, from_name, to_ns_quark);
261 if (ret == NULL) {
262 ret = lasso_registry_get_direct_mapping(registry->direct_mapping, from_ns_quark, from_name, to_ns_quark);
263 }
264
265 return ret;
266 }
267
268 /**
269 * lasso_registry_add_direct_mapping:
270 *
271 * Add a new mapping from a QName to a QName.
272 *
273 * Return value: 0 if successfull, LASSO_REGISTRY_ERROR_KEY_EXISTS if it already exists,
274 * LASSO_PARAM_ERROR_INVALID_VALUE if arguments
275 * are invalid.
276 */
lasso_registry_add_direct_mapping(LassoRegistry * registry,const char * from_namespace,const char * from_name,const char * to_namespace,const char * to_name)277 gint lasso_registry_add_direct_mapping(LassoRegistry *registry, const char *from_namespace,
278 const char *from_name, const char *to_namespace, const char *to_name)
279 {
280 LassoRegistryDirectMappingRecord *a_record;
281
282 g_return_val_if_fail(registry && from_namespace && from_name && to_namespace && to_name, LASSO_PARAM_ERROR_INVALID_VALUE);
283
284 if (lasso_registry_get_mapping(registry, from_namespace, from_name, to_namespace)) {
285 return LASSO_REGISTRY_ERROR_KEY_EXISTS;
286 }
287 a_record = g_new0(LassoRegistryDirectMappingRecord, 1);
288 a_record->from_namespace = g_quark_from_string(from_namespace);
289 a_record->from_name = g_quark_from_string(from_name);
290 a_record->to_namespace = g_quark_from_string(to_namespace);
291 a_record->to_name = g_quark_from_string(to_name);
292 g_hash_table_insert(registry->direct_mapping, a_record, a_record);
293 return 0;
294 }
295
296 /**
297 * lasso_registry_add_functional_mapping:
298 * @registry: a #LassoRegistry
299 * @from_namespace: URI of the source namespace
300 * @to_namespace: URI of the destination namespace
301 * @translation_function: a function mapping string to string from the first namespace to the second one
302 *
303 * Register a new mapping from from_namesapce to to_namespace using the
304 * translation_function. This functions is not forced to return a value for
305 * any string, it can return NULL.
306 *
307 * Return value: 0 if successfull, LASSO_REGISTRY_ERROR_KEY_EXISTS if this mapping is already registered,
308 * LASSO_PARAM_ERROR_INVALID_VALUE if one the argument is invalid.
309 */
lasso_registry_add_functional_mapping(LassoRegistry * registry,const char * from_namespace,const char * to_namespace,LassoRegistryTranslationFunction translation_function)310 gint lasso_registry_add_functional_mapping(LassoRegistry *registry, const char *from_namespace,
311 const char *to_namespace, LassoRegistryTranslationFunction translation_function)
312 {
313 LassoRegistryFunctionalMappingRecord *a_record;
314 GQuark to_ns_quark, from_ns_quark;
315
316 g_return_val_if_fail(registry != NULL && from_namespace != NULL && to_namespace != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
317 from_ns_quark = g_quark_from_string(from_namespace);
318 to_ns_quark = g_quark_from_string(to_namespace);
319 if (lasso_registry_get_translation_function(registry->functional_mapping, from_ns_quark, to_ns_quark)) {
320 return LASSO_REGISTRY_ERROR_KEY_EXISTS;
321 }
322 a_record = g_new0(LassoRegistryFunctionalMappingRecord, 1);
323 a_record->from_namespace = from_ns_quark;
324 a_record->to_namespace = to_ns_quark;
325 a_record->translation_function = translation_function;
326
327 g_hash_table_insert(registry->functional_mapping, a_record, a_record);
328
329 return 0;
330 }
331
332 /**
333 * lasso_registry_default_add_direct_mapping:
334 * @from_namespace: the namespace of the mapped QName
335 * @from_name: the name of the mapped QName
336 * @to_namespace: the namepsace of the mapped to QName
337 * @to_name: the name of the mapped to QName
338 *
339 * Add a new mapping from a QName to a QName.
340 *
341 * Return value: 0 if successfull, LASSO_REGISTRY_ERROR_KEY_EXISTS if this mapping is already registered,
342 * LASSO_PARAM_ERROR_INVALID_VALUE if one the argument is invalid.
343 */
lasso_registry_default_add_direct_mapping(const char * from_namespace,const char * from_name,const char * to_namespace,const char * to_name)344 gint lasso_registry_default_add_direct_mapping(const char *from_namespace,
345 const char *from_name, const char *to_namespace, const char *to_name)
346 {
347 LassoRegistry *default_registry = lasso_registry_get_default();
348
349 return lasso_registry_add_direct_mapping(default_registry, from_namespace, from_name, to_namespace, to_name);
350 }
351
352 /**
353 * lasso_registry_default_add_functional_mapping:
354 *
355 * @from_namespace: URI of the source namespace
356 * @to_namespace: URI of the destination namespace
357 * @translation_function: a function mapping string to string from the first namespace to the second one
358 *
359 * Register a new mapping from from_namesapce to to_namespace using the translation_function into
360 * the default mapping. This functions is not forced to return a value for any string, it can return
361 * NULL.
362 *
363 * Return value: 0 if successfull, LASSO_REGISTRY_ERROR_KEY_EXISTS if this mapping is already registered,
364 * LASSO_PARAM_ERROR_INVALID_VALUE if one the argument is invalid.
365 */
lasso_registry_default_add_functional_mapping(const char * from_namespace,const char * to_namespace,LassoRegistryTranslationFunction translation_function)366 gint lasso_registry_default_add_functional_mapping(const char *from_namespace,
367 const char *to_namespace, LassoRegistryTranslationFunction translation_function)
368 {
369 LassoRegistry *default_registry = lasso_registry_get_default();
370
371 return lasso_registry_add_functional_mapping(default_registry, from_namespace, to_namespace, translation_function);
372 }
373
374
375 /**
376 * lasso_registry_default_get_mapping:
377 * @from_namespace: the namespace of the mapped QName
378 * @from_name: the name of the mapped QName
379 * @to_namespace: the namepsace of the mapped to QName
380 *
381 * Retrieve the name of the QName in the namespace to_namespace that maps the
382 * QName from_namespace:from_name.
383 *
384 * Return value: the name string of the QName or NULL if no mapping exists.
385 */
lasso_registry_default_get_mapping(const char * from_namespace,const char * from_name,const char * to_namespace)386 const char* lasso_registry_default_get_mapping(const char *from_namespace,
387 const char *from_name, const char *to_namespace)
388 {
389 LassoRegistry *default_registry = lasso_registry_get_default();
390
391 return lasso_registry_get_mapping(default_registry, from_namespace, from_name, to_namespace);
392 }
393