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 }