tracker-0.16.2/src/libtracker-data/tracker-ontologies.c

No issues found

  1 /*
  2  * Copyright (C) 2006, Jamie McCracken <jamiemcc@gnome.org>
  3  * Copyright (C) 2008, Nokia <ivan.frade@nokia.com>
  4  *
  5  * This library is free software; you can redistribute it and/or
  6  * modify it under the terms of the GNU Lesser General Public
  7  * License as published by the Free Software Foundation; either
  8  * version 2.1 of the License, or (at your option) any later version.
  9  *
 10  * This library is distributed in the hope that it will be useful,
 11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  * Lesser General Public License for more details.
 14  *
 15  * You should have received a copy of the GNU Lesser General Public
 16  * License along with this library; if not, write to the
 17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 18  * Boston, MA  02110-1301, USA.
 19  */
 20 
 21 #include "config.h"
 22 
 23 #include <string.h>
 24 #include <stdlib.h>
 25 
 26 #include <glib.h>
 27 
 28 #include <gvdb/gvdb-builder.h>
 29 #include <gvdb/gvdb-reader.h>
 30 #include <libtracker-common/tracker-ontologies.h>
 31 
 32 #include "tracker-ontologies.h"
 33 
 34 static gboolean    initialized;
 35 
 36 /* List of TrackerNamespace objects */
 37 static GPtrArray  *namespaces;
 38 
 39 /* Namespace uris */
 40 static GHashTable *namespace_uris;
 41 
 42 /* List of TrackerOntology objects */
 43 static GPtrArray  *ontologies;
 44 
 45 /* Ontology uris */
 46 static GHashTable *ontology_uris;
 47 
 48 /* List of TrackerClass objects */
 49 static GPtrArray  *classes;
 50 
 51 /* Hash (gchar *class_uri, TrackerClass *service) */
 52 static GHashTable *class_uris;
 53 
 54 /* List of TrackerProperty objects */
 55 static GPtrArray  *properties;
 56 
 57 /* Field uris */
 58 static GHashTable *property_uris;
 59 
 60 /* FieldType enum class */
 61 static gpointer    property_type_enum_class;
 62 
 63 /* Hash (int id, const gchar *uri) */
 64 static GHashTable *id_uri_pairs;
 65 
 66 /* rdf:type */
 67 static TrackerProperty *rdf_type = NULL;
 68 
 69 static GvdbTable *gvdb_table;
 70 static GvdbTable *gvdb_namespaces_table;
 71 static GvdbTable *gvdb_classes_table;
 72 static GvdbTable *gvdb_properties_table;
 73 
 74 void
 75 tracker_ontologies_init (void)
 76 {
 77 	if (initialized) {
 78 		return;
 79 	}
 80 
 81 	namespaces = g_ptr_array_new ();
 82 
 83 	ontologies = g_ptr_array_new ();
 84 
 85 	namespace_uris = g_hash_table_new_full (g_str_hash,
 86 	                                        g_str_equal,
 87 	                                        g_free,
 88 	                                        g_object_unref);
 89 
 90 	ontology_uris = g_hash_table_new_full (g_str_hash,
 91 	                                       g_str_equal,
 92 	                                       g_free,
 93 	                                       g_object_unref);
 94 
 95 	classes = g_ptr_array_new ();
 96 
 97 	class_uris = g_hash_table_new_full (g_str_hash,
 98 	                                    g_str_equal,
 99 	                                    g_free,
100 	                                    g_object_unref);
101 
102 	id_uri_pairs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
103 	                                      NULL,
104 	                                      g_free);
105 
106 	properties = g_ptr_array_new ();
107 
108 	property_uris = g_hash_table_new_full (g_str_hash,
109 	                                       g_str_equal,
110 	                                       g_free,
111 	                                       g_object_unref);
112 
113 	/* We will need the class later in order to match strings to enum values
114 	 * when inserting metadata types in the DB, so the enum class needs to be
115 	 * created beforehand.
116 	 */
117 	property_type_enum_class = g_type_class_ref (TRACKER_TYPE_PROPERTY_TYPE);
118 
119 	initialized = TRUE;
120 }
121 
122 void
123 tracker_ontologies_shutdown (void)
124 {
125 	if (!initialized) {
126 		return;
127 	}
128 
129 	g_ptr_array_foreach (namespaces, (GFunc) g_object_unref, NULL);
130 	g_ptr_array_free (namespaces, TRUE);
131 
132 	g_hash_table_unref (namespace_uris);
133 	namespace_uris = NULL;
134 
135 	g_ptr_array_foreach (ontologies, (GFunc) g_object_unref, NULL);
136 	g_ptr_array_free (ontologies, TRUE);
137 
138 	g_hash_table_unref (ontology_uris);
139 	ontology_uris = NULL;
140 
141 	g_ptr_array_foreach (classes, (GFunc) g_object_unref, NULL);
142 	g_ptr_array_free (classes, TRUE);
143 
144 	g_hash_table_unref (class_uris);
145 	class_uris = NULL;
146 
147 	g_hash_table_unref (id_uri_pairs);
148 	id_uri_pairs = NULL;
149 
150 	g_ptr_array_foreach (properties, (GFunc) g_object_unref, NULL);
151 	g_ptr_array_free (properties, TRUE);
152 
153 	g_hash_table_unref (property_uris);
154 	property_uris = NULL;
155 
156 	g_type_class_unref (property_type_enum_class);
157 	property_type_enum_class = NULL;
158 
159 	if (rdf_type) {
160 		g_object_unref (rdf_type);
161 		rdf_type = NULL;
162 	}
163 
164 	if (gvdb_table) {
165 		gvdb_table_unref (gvdb_properties_table);
166 		gvdb_properties_table = NULL;
167 
168 		gvdb_table_unref (gvdb_classes_table);
169 		gvdb_classes_table = NULL;
170 
171 		gvdb_table_unref (gvdb_namespaces_table);
172 		gvdb_namespaces_table = NULL;
173 
174 		gvdb_table_unref (gvdb_table);
175 		gvdb_table = NULL;
176 	}
177 
178 	initialized = FALSE;
179 }
180 
181 TrackerProperty *
182 tracker_ontologies_get_rdf_type (void)
183 {
184 	g_return_val_if_fail (rdf_type != NULL, NULL);
185 
186 	return rdf_type;
187 }
188 
189 const gchar*
190 tracker_ontologies_get_uri_by_id (gint id)
191 {
192 	g_return_val_if_fail (id != -1, NULL);
193 
194 	return g_hash_table_lookup (id_uri_pairs, GINT_TO_POINTER (id));
195 }
196 
197 void
198 tracker_ontologies_add_class (TrackerClass *service)
199 {
200 
201 	const gchar *uri;
202 
203 	g_return_if_fail (TRACKER_IS_CLASS (service));
204 
205 	uri = tracker_class_get_uri (service);
206 
207 	g_ptr_array_add (classes, g_object_ref (service));
208 
209 	if (uri) {
210 		g_hash_table_insert (class_uris,
211 		                     g_strdup (uri),
212 		                     g_object_ref (service));
213 	}
214 }
215 
216 TrackerClass *
217 tracker_ontologies_get_class_by_uri (const gchar *class_uri)
218 {
219 	TrackerClass *class;
220 
221 	g_return_val_if_fail (class_uri != NULL, NULL);
222 
223 	class = g_hash_table_lookup (class_uris, class_uri);
224 
225 	if (!class && gvdb_table) {
226 		if (tracker_ontologies_get_class_string_gvdb (class_uri, "name") != NULL) {
227 			class = tracker_class_new (TRUE);
228 			tracker_class_set_uri (class, class_uri);
229 
230 			g_hash_table_insert (class_uris,
231 				             g_strdup (class_uri),
232 				             class);
233 		}
234 	}
235 
236 	return class;
237 }
238 
239 TrackerNamespace **
240 tracker_ontologies_get_namespaces (guint *length)
241 {
242 	if (namespaces->len == 0 && gvdb_table) {
243 		gchar **namespace_uris;
244 		gint i;
245 
246 		namespace_uris = gvdb_table_list (gvdb_namespaces_table, "");
247 
248 		for (i = 0; namespace_uris[i]; i++) {
249 			TrackerNamespace *namespace;
250 
251 			namespace = tracker_ontologies_get_namespace_by_uri (namespace_uris[i]);
252 
253 			g_ptr_array_add (namespaces, g_object_ref (namespace));
254 		}
255 
256 		g_strfreev (namespace_uris);
257 	}
258 
259 	*length = namespaces->len;
260 	return (TrackerNamespace **) namespaces->pdata;
261 }
262 
263 TrackerOntology **
264 tracker_ontologies_get_ontologies (guint *length)
265 {
266 	if (G_UNLIKELY (!ontologies)) {
267 		*length = 0;
268 		return NULL;
269 	}
270 
271 	*length = ontologies->len;
272 	return (TrackerOntology **) ontologies->pdata;
273 }
274 
275 TrackerClass **
276 tracker_ontologies_get_classes (guint *length)
277 {
278 	if (classes->len == 0 && gvdb_table) {
279 		gchar **class_uris;
280 		gint i;
281 
282 		class_uris = gvdb_table_list (gvdb_classes_table, "");
283 
284 		for (i = 0; class_uris[i]; i++) {
285 			TrackerClass *class;
286 
287 			class = tracker_ontologies_get_class_by_uri (class_uris[i]);
288 
289 			g_ptr_array_add (classes, g_object_ref (class));
290 		}
291 
292 		g_strfreev (class_uris);
293 	}
294 
295 	*length = classes->len;
296 	return (TrackerClass **) classes->pdata;
297 }
298 
299 TrackerProperty **
300 tracker_ontologies_get_properties (guint *length)
301 {
302 	if (properties->len == 0 && gvdb_table) {
303 		gchar **property_uris;
304 		gint i;
305 
306 		property_uris = gvdb_table_list (gvdb_properties_table, "");
307 
308 		for (i = 0; property_uris[i]; i++) {
309 			TrackerProperty *property;
310 
311 			property = tracker_ontologies_get_property_by_uri (property_uris[i]);
312 
313 			g_ptr_array_add (properties, g_object_ref (property));
314 		}
315 
316 		g_strfreev (property_uris);
317 	}
318 
319 	*length = properties->len;
320 	return (TrackerProperty **) properties->pdata;
321 }
322 
323 /* Field mechanics */
324 void
325 tracker_ontologies_add_property (TrackerProperty *field)
326 {
327 	const gchar *uri;
328 
329 	g_return_if_fail (TRACKER_IS_PROPERTY (field));
330 
331 	uri = tracker_property_get_uri (field);
332 
333 	if (g_strcmp0 (uri, TRACKER_RDF_PREFIX "type") == 0) {
334 		if (rdf_type) {
335 			g_object_unref (rdf_type);
336 		}
337 		rdf_type = g_object_ref (field);
338 	}
339 
340 	g_ptr_array_add (properties, g_object_ref (field));
341 
342 	g_hash_table_insert (property_uris,
343 	                     g_strdup (uri),
344 	                     g_object_ref (field));
345 }
346 
347 void
348 tracker_ontologies_add_id_uri_pair (gint id, const gchar *uri)
349 {
350 	g_hash_table_insert (id_uri_pairs,
351 	                     GINT_TO_POINTER (id),
352 	                     g_strdup (uri));
353 }
354 
355 TrackerProperty *
356 tracker_ontologies_get_property_by_uri (const gchar *uri)
357 {
358 	TrackerProperty *property;
359 
360 	g_return_val_if_fail (uri != NULL, NULL);
361 
362 	property = g_hash_table_lookup (property_uris, uri);
363 
364 	if (!property && gvdb_table) {
365 		if (tracker_ontologies_get_property_string_gvdb (uri, "name") != NULL) {
366 			property = tracker_property_new (TRUE);
367 			tracker_property_set_uri (property, uri);
368 
369 			g_hash_table_insert (property_uris,
370 				             g_strdup (uri),
371 				             property);
372 		}
373 	}
374 
375 	return property;
376 }
377 
378 void
379 tracker_ontologies_add_namespace (TrackerNamespace *namespace)
380 {
381 	const gchar *uri;
382 
383 	g_return_if_fail (TRACKER_IS_NAMESPACE (namespace));
384 
385 	uri = tracker_namespace_get_uri (namespace);
386 
387 	g_ptr_array_add (namespaces, g_object_ref (namespace));
388 
389 	g_hash_table_insert (namespace_uris,
390 	                     g_strdup (uri),
391 	                     g_object_ref (namespace));
392 }
393 
394 void
395 tracker_ontologies_add_ontology (TrackerOntology *ontology)
396 {
397 	const gchar *uri;
398 
399 	g_return_if_fail (TRACKER_IS_ONTOLOGY (ontology));
400 
401 	uri = tracker_ontology_get_uri (ontology);
402 
403 	g_ptr_array_add (ontologies, g_object_ref (ontology));
404 
405 	g_hash_table_insert (ontology_uris,
406 	                     g_strdup (uri),
407 	                     g_object_ref (ontology));
408 }
409 
410 TrackerNamespace *
411 tracker_ontologies_get_namespace_by_uri (const gchar *uri)
412 {
413 	TrackerNamespace *namespace;
414 
415 	g_return_val_if_fail (uri != NULL, NULL);
416 
417 	namespace = g_hash_table_lookup (namespace_uris, uri);
418 
419 	if (!namespace && gvdb_table) {
420 		if (tracker_ontologies_get_namespace_string_gvdb (uri, "prefix") != NULL) {
421 			namespace = tracker_namespace_new (TRUE);
422 			tracker_namespace_set_uri (namespace, uri);
423 
424 			g_hash_table_insert (namespace_uris,
425 					     g_strdup (uri),
426 					     namespace);
427 		}
428 	}
429 
430 	return namespace;
431 }
432 
433 
434 TrackerOntology *
435 tracker_ontologies_get_ontology_by_uri (const gchar *uri)
436 {
437 	g_return_val_if_fail (uri != NULL, NULL);
438 
439 	return g_hash_table_lookup (ontology_uris, uri);
440 }
441 
442 static void
443 gvdb_hash_table_insert_variant (GHashTable  *table,
444                                 GvdbItem    *parent,
445                                 const gchar *uri,
446                                 const gchar *predicate,
447                                 GVariant    *value)
448 {
449 	gchar *key;
450 	GvdbItem *item;
451 
452 	key = g_strdup_printf ("%s#%s", uri, predicate);
453 	item = gvdb_hash_table_insert (table, key);
454 	gvdb_item_set_parent (item, parent);
455 	gvdb_item_set_value (item, value);
456 	g_free (key);
457 }
458 
459 static GvdbItem *
460 gvdb_hash_table_insert_item (GHashTable *table,
461                              GvdbItem   *root,
462                              const gchar *uri)
463 {
464 	GvdbItem *item;
465 
466 	item = gvdb_hash_table_insert (table, uri);
467 	gvdb_item_set_parent (item, root);
468 
469 	return item;
470 }
471 
472 static void
473 gvdb_hash_table_insert_statement (GHashTable  *table,
474                                   GvdbItem    *parent,
475                                   const gchar *uri,
476                                   const gchar *predicate,
477                                   const gchar *value)
478 {
479 	gvdb_hash_table_insert_variant (table, parent, uri, predicate, g_variant_new_string (value));
480 }
481 
482 void
483 tracker_ontologies_write_gvdb (const gchar  *filename,
484                                GError      **error)
485 {
486 	GHashTable *root_table, *table;
487 	GvdbItem *root, *item;
488 	const gchar *uri;
489 	gint i;
490 
491 	root_table = gvdb_hash_table_new (NULL, NULL);
492 
493 	table = gvdb_hash_table_new (root_table, "namespaces");
494 	root = gvdb_hash_table_insert (table, "");
495 	for (i = 0; i < namespaces->len; i++) {
496 		TrackerNamespace *namespace;
497 
498 		namespace = namespaces->pdata[i];
499 		uri = tracker_namespace_get_uri (namespace);
500 
501 		item = gvdb_hash_table_insert_item (table, root, uri);
502 
503 		gvdb_hash_table_insert_statement (table, item, uri, "prefix", tracker_namespace_get_prefix (namespace));
504 	}
505 	g_hash_table_unref (table);
506 
507 	table = gvdb_hash_table_new (root_table, "classes");
508 	root = gvdb_hash_table_insert (table, "");
509 	for (i = 0; i < classes->len; i++) {
510 		TrackerClass *class;
511 		TrackerClass **super_classes;
512 		GVariantBuilder builder;
513 
514 		class = classes->pdata[i];
515 		uri = tracker_class_get_uri (class);
516 
517 		item = gvdb_hash_table_insert_item (table, root, uri);
518 
519 		gvdb_hash_table_insert_statement (table, item, uri, "name", tracker_class_get_name (class));
520 
521 		super_classes = tracker_class_get_super_classes (class);
522 		if (super_classes) {
523 			g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
524 
525 			while (*super_classes) {
526 				g_variant_builder_add (&builder, "s", tracker_class_get_uri (*super_classes));
527 				super_classes++;
528 			}
529 
530 			gvdb_hash_table_insert_variant (table, item, uri, "super-classes", g_variant_builder_end (&builder));
531 		}
532 	}
533 	g_hash_table_unref (table);
534 
535 	table = gvdb_hash_table_new (root_table, "properties");
536 	root = gvdb_hash_table_insert (table, "");
537 	for (i = 0; i < properties->len; i++) {
538 		TrackerProperty *property;
539 		TrackerClass **domain_indexes;
540 		GVariantBuilder builder;
541 
542 		property = properties->pdata[i];
543 		uri = tracker_property_get_uri (property);
544 
545 		item = gvdb_hash_table_insert_item (table, root, uri);
546 
547 		gvdb_hash_table_insert_statement (table, item, uri, "name", tracker_property_get_name (property));
548 		gvdb_hash_table_insert_statement (table, item, uri, "domain", tracker_class_get_uri (tracker_property_get_domain (property)));
549 		gvdb_hash_table_insert_statement (table, item, uri, "range", tracker_class_get_uri (tracker_property_get_range (property)));
550 
551 		if (!tracker_property_get_multiple_values (property)) {
552 			gvdb_hash_table_insert_variant (table, item, uri, "max-cardinality", g_variant_new_int32 (1));
553 		}
554 
555 		if (tracker_property_get_is_inverse_functional_property (property)) {
556 			gvdb_hash_table_insert_variant (table, item, uri, "inverse-functional", g_variant_new_boolean (TRUE));
557 		}
558 
559 		domain_indexes = tracker_property_get_domain_indexes (property);
560 		if (domain_indexes) {
561 			g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
562 
563 			while (*domain_indexes) {
564 				g_variant_builder_add (&builder, "s", tracker_class_get_uri (*domain_indexes));
565 				domain_indexes++;
566 			}
567 
568 			gvdb_hash_table_insert_variant (table, item, uri, "domain-indexes", g_variant_builder_end (&builder));
569 		}
570 	}
571 	g_hash_table_unref (table);
572 
573 	gvdb_table_write_contents (root_table, filename, FALSE, error);
574 
575 	g_hash_table_unref (root_table);
576 }
577 
578 void
579 tracker_ontologies_load_gvdb (const gchar  *filename,
580                               GError      **error)
581 {
582 	tracker_ontologies_shutdown ();
583 
584 	tracker_ontologies_init ();
585 
586 	gvdb_table = gvdb_table_new (filename, TRUE, error);
587 	if (!gvdb_table) {
588 		return;
589 	}
590 
591 	gvdb_namespaces_table = gvdb_table_get_table (gvdb_table, "namespaces");
592 	gvdb_classes_table = gvdb_table_get_table (gvdb_table, "classes");
593 	gvdb_properties_table = gvdb_table_get_table (gvdb_table, "properties");
594 }
595 
596 GVariant *
597 tracker_ontologies_get_namespace_value_gvdb (const gchar *uri,
598                                              const gchar *predicate)
599 {
600 	gchar *key;
601 	GVariant *value;
602 
603 	key = g_strdup_printf ("%s#%s", uri, predicate);
604 	value = gvdb_table_get_value (gvdb_namespaces_table, key);
605 	g_free (key);
606 
607 	return value;
608 }
609 
610 const gchar *
611 tracker_ontologies_get_namespace_string_gvdb (const gchar *uri,
612                                               const gchar *predicate)
613 {
614 	GVariant *value;
615 	const gchar *result;
616 
617 	value = tracker_ontologies_get_namespace_value_gvdb (uri, predicate);
618 
619 	if (value == NULL) {
620 		return NULL;
621 	}
622 
623 	result = g_variant_get_string (value, NULL);
624 	g_variant_unref (value);
625 
626 	return result;
627 }
628 
629 GVariant *
630 tracker_ontologies_get_class_value_gvdb (const gchar *uri,
631                                          const gchar *predicate)
632 {
633 	gchar *key;
634 	GVariant *value;
635 
636 	key = g_strdup_printf ("%s#%s", uri, predicate);
637 	value = gvdb_table_get_value (gvdb_classes_table, key);
638 	g_free (key);
639 
640 	return value;
641 }
642 
643 const gchar *
644 tracker_ontologies_get_class_string_gvdb (const gchar *uri,
645                                           const gchar *predicate)
646 {
647 	GVariant *value;
648 	const gchar *result;
649 
650 	value = tracker_ontologies_get_class_value_gvdb (uri, predicate);
651 
652 	if (value == NULL) {
653 		return NULL;
654 	}
655 
656 	result = g_variant_get_string (value, NULL);
657 	g_variant_unref (value);
658 
659 	return result;
660 }
661 
662 GVariant *
663 tracker_ontologies_get_property_value_gvdb (const gchar *uri,
664                                             const gchar *predicate)
665 {
666 	gchar *key;
667 	GVariant *value;
668 
669 	key = g_strdup_printf ("%s#%s", uri, predicate);
670 	value = gvdb_table_get_value (gvdb_properties_table, key);
671 	g_free (key);
672 
673 	return value;
674 }
675 
676 const gchar *
677 tracker_ontologies_get_property_string_gvdb (const gchar *uri,
678                                              const gchar *predicate)
679 {
680 	GVariant *value;
681 	const gchar *result;
682 
683 	value = tracker_ontologies_get_property_value_gvdb (uri, predicate);
684 
685 	if (value == NULL) {
686 		return NULL;
687 	}
688 
689 	result = g_variant_get_string (value, NULL);
690 	g_variant_unref (value);
691 
692 	return result;
693 }
694 
695 static gint
696 class_sort_func (gconstpointer a,
697                  gconstpointer b)
698 {
699 	return g_strcmp0 (tracker_class_get_name (*((TrackerClass **) a)),
700 	                  tracker_class_get_name (*((TrackerClass **) b)));
701 }
702 
703 void
704 tracker_ontologies_sort (void)
705 {
706 	/* Sort result so it is alphabetical */
707 	g_ptr_array_sort (classes, class_sort_func);
708 }