No issues found
1 /*
2 * Copyright (C) 2009, Nokia <ivan.frade@nokia.com>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20 #include "ttl_loader.h"
21 #include <glib/gstdio.h>
22
23 #include <libtracker-data/tracker-sparql-query.h>
24
25 /* Ontology classes */
26 #define RDFS_CLASS "http://www.w3.org/2000/01/rdf-schema#Class"
27 #define RDF_PROPERTY "http://www.w3.org/1999/02/22-rdf-syntax-ns#Property"
28 #define RDFS_SUBCLASSOF "http://www.w3.org/2000/01/rdf-schema#subClassOf"
29 #define RDFS_TYPE "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
30 #define RDFS_RANGE "http://www.w3.org/2000/01/rdf-schema#range"
31 #define RDFS_DOMAIN "http://www.w3.org/2000/01/rdf-schema#domain"
32 #define RDFS_COMMENT "http://www.w3.org/2000/01/rdf-schema#comment"
33 #define RDFS_LABEL "http://www.w3.org/2000/01/rdf-schema#label"
34 #define RDFS_SUBPROPERTYOF "http://www.w3.org/2000/01/rdf-schema#subPropertyOf"
35
36 #define NRL_MAX_CARDINALITY "http://www.semanticdesktop.org/ontologies/2007/08/15/nrl#maxCardinality"
37
38 /* #define TRACKER_NAMESPACE "http://www.tracker-project.org/ontologies/tracker#Namespace" */
39 #define TRACKER_NS "http://www.tracker-project.org/ontologies/tracker#"
40 #define TRACKER_NOTIFY TRACKER_NS "notify"
41 #define TRACKER_FTS_INDEXED TRACKER_NS "fulltextIndexed"
42 #define TRACKER_FTS_WEIGHT TRACKER_NS "weight"
43
44 #define NAO_DEPRECATED "http://www.semanticdesktop.org/ontologies/2007/08/15/nao#deprecated"
45
46 /* Ontology description */
47 #define DSC_PREFIX "http://www.tracker-project.org/temp/dsc#"
48
49 #define DSC_ONTOLOGY DSC_PREFIX "Ontology"
50 #define DSC_TITLE DSC_PREFIX "title"
51 #define DSC_DESCRIPTION DSC_PREFIX "description"
52 #define DSC_AUTHOR DSC_PREFIX "author"
53 #define DSC_EDITOR DSC_PREFIX "editor"
54 #define DSC_CONTRIBUTOR DSC_PREFIX "contributor"
55 #define DSC_GITLOG DSC_PREFIX "gitlog"
56 #define DSC_UPSTREAM DSC_PREFIX "upstream"
57 #define DSC_BASEURI DSC_PREFIX "baseUrl"
58 #define DSC_RELPATH DSC_PREFIX "relativePath"
59 #define DSC_LOCALPREFIX DSC_PREFIX "localPrefix"
60 #define DSC_COPYRIGHT DSC_PREFIX "copyright"
61
62 static gboolean
63 string_to_boolean (const gchar *str) {
64 if (!g_strcmp0 (str, "true")) {
65 return TRUE;
66 } else if (!g_strcmp0 (str, "false")) {
67 return FALSE;
68 } else {
69 g_error ("Unable to map '%s' into boolean", str);
70 }
71 }
72
73
74 static void
75 load_in_memory (Ontology *ontology,
76 const gchar *turtle_subject,
77 const gchar *turtle_predicate,
78 const gchar *turtle_object)
79 {
80 g_return_if_fail (ontology != NULL);
81
82 if (!g_strcmp0 (turtle_predicate, RDFS_TYPE)) {
83 /* It is a definition of class or property */
84 if (!g_strcmp0 (turtle_object, RDFS_CLASS)) {
85 g_hash_table_insert (ontology->classes,
86 g_strdup (turtle_subject),
87 ttl_model_class_new (turtle_subject));
88
89 } else if (!g_strcmp0 (turtle_object, RDF_PROPERTY)) {
90 g_hash_table_insert (ontology->properties,
91 g_strdup (turtle_subject),
92 ttl_model_property_new (turtle_subject));
93
94 } else {
95 /* xxx:a-default-instance a xxx:Class */
96 OntologyClass *def;
97
98 def = g_hash_table_lookup (ontology->classes, turtle_object);
99 if (def) {
100 def->instances = g_list_prepend (def->instances,
101 g_strdup (turtle_subject));
102 }
103 /* g_print ("FIXME Ignoring %s %s %s\n",
104 turtle_subject, turtle_predicate, turtle_object);
105 */
106 }
107
108 } else if (!g_strcmp0 (turtle_predicate, RDFS_SUBCLASSOF)) {
109 /*
110 * A subclass of B:
111 * - Add B in A->superclasses list
112 * - Add A in B->subclasses list (if B is in this ontology!)
113 */
114 OntologyClass *def;
115
116 def = g_hash_table_lookup (ontology->classes, turtle_subject);
117 if (!def) {
118 g_error ("Something wrong");
119 }
120
121 def->superclasses = g_list_prepend (def->superclasses,
122 g_strdup (turtle_object));
123
124 def = g_hash_table_lookup (ontology->classes, turtle_object);
125 if (def) {
126 def->subclasses = g_list_prepend (def->subclasses,
127 g_strdup (turtle_subject));
128 }
129 } else if (!g_strcmp0 (turtle_predicate, TRACKER_NOTIFY)) {
130 /*
131 * A tracker:notify TRUE
132 */
133 OntologyClass *def;
134
135 def = g_hash_table_lookup (ontology->classes, turtle_subject);
136 if (!def) {
137 g_error ("Something wrong");
138 }
139
140 def->notify = string_to_boolean (turtle_object);
141
142 } else if (!g_strcmp0 (turtle_predicate, TRACKER_FTS_INDEXED)) {
143 /*
144 * A tracker:fulltextIndexed TRUE
145 */
146 OntologyProperty *prop;
147
148 prop = g_hash_table_lookup (ontology->properties, turtle_subject);
149 if (!prop) {
150 g_error ("Something wrong");
151 }
152
153 prop->fulltextIndexed = string_to_boolean (turtle_object);
154
155 } else if (!g_strcmp0 (turtle_predicate, TRACKER_FTS_WEIGHT)) {
156 /*
157 * A tracker:weight X
158 */
159 OntologyProperty *prop;
160
161 prop = g_hash_table_lookup (ontology->properties, turtle_subject);
162 if (!prop) {
163 g_error ("Something wrong");
164 }
165
166 prop->weight = g_strdup (turtle_object);
167
168 } else if (!g_strcmp0 (turtle_predicate, RDFS_COMMENT)) {
169 OntologyClass *klass;
170 OntologyProperty *prop;
171
172 klass = g_hash_table_lookup (ontology->classes, turtle_subject);
173 if (klass) {
174 klass->description = g_strdup (turtle_object);
175 } else {
176 prop = g_hash_table_lookup (ontology->properties, turtle_subject);
177 if (prop) {
178 prop->description = g_strdup (turtle_object);
179 } else {
180 g_error ("UHUMMM %s", turtle_subject);
181 }
182 }
183
184 } else if (!g_strcmp0 (turtle_predicate, RDFS_DOMAIN)) {
185 /*
186 * (prop A) has domain (class B)
187 * -> add B in A->domain
188 * -> add A in B->in_domain_of (if B is defined in this ontology!)
189 */
190 OntologyProperty *prop;
191 OntologyClass *klass;
192
193 prop = g_hash_table_lookup (ontology->properties, turtle_subject);
194 if (!prop) {
195 g_error ("Strange error in domain (%s doesnt exist!)",
196 turtle_subject);
197 }
198 prop->domain = g_list_prepend (prop->domain, g_strdup (turtle_object));
199
200 klass = g_hash_table_lookup (ontology->classes, turtle_object);
201 if (klass) {
202 klass->in_domain_of = g_list_prepend (klass->in_domain_of,
203 g_strdup (turtle_subject));
204 }
205
206 } else if (!g_strcmp0 (turtle_predicate, RDFS_RANGE)) {
207 /*
208 * (prop A) has range (class B)
209 * -> add B in A->range
210 * -> add A in B->in_range_of (if B is defined in this ontology!)
211 */
212 OntologyProperty *prop;
213 OntologyClass *klass;
214
215 prop = g_hash_table_lookup (ontology->properties, turtle_subject);
216 if (!prop) {
217 g_error ("Strange error in domain (%s doesnt exist!)",
218 turtle_subject);
219 }
220 prop->range = g_list_prepend (prop->range, g_strdup (turtle_object));
221
222 klass = g_hash_table_lookup (ontology->classes, turtle_object);
223 if (klass) {
224 klass->in_range_of = g_list_prepend (klass->in_range_of,
225 g_strdup (turtle_subject));
226 }
227 } else if (!g_strcmp0 (turtle_predicate, NRL_MAX_CARDINALITY)) {
228 OntologyProperty *prop;
229
230 prop = g_hash_table_lookup (ontology->properties, turtle_subject);
231 if (!prop) {
232 g_error ("Strange error in max cardinality (%s doesnt exist!)",
233 turtle_subject);
234 }
235 prop->max_cardinality = g_strdup (turtle_object);
236
237 } else if (!g_strcmp0 (turtle_predicate, RDFS_SUBPROPERTYOF)) {
238 /*
239 * (prop A) is subproperty of (prop B)
240 * -> add B in A->superproperties
241 * -> add A in B->subproperties (if B is in this ontology)
242 */
243 OntologyProperty *propA, *propB;
244
245 propA = g_hash_table_lookup (ontology->properties, turtle_subject);
246 if (!propA) {
247 g_error ("Strange error in subpropertyof (%s doesnt exist!)",
248 turtle_subject);
249 }
250 propA->superproperties = g_list_prepend (propA->superproperties,
251 g_strdup (turtle_object));
252
253 propB = g_hash_table_lookup (ontology->properties, turtle_object);
254 if (propB) {
255 propB->subproperties = g_list_prepend (propB->subproperties,
256 g_strdup (turtle_subject));
257 }
258
259 } else if (!g_strcmp0 (turtle_predicate, NAO_DEPRECATED)) {
260 /*
261 * X nao:deprecated true
262 *
263 * This can apply to classes OR properties!
264 */
265 OntologyProperty *prop;
266 OntologyClass *klass;
267
268 prop = g_hash_table_lookup (ontology->properties, turtle_subject);
269 if (prop) {
270 prop->deprecated = string_to_boolean (turtle_object);
271 } else {
272 /* Try with a class */
273 klass = g_hash_table_lookup (ontology->classes, turtle_subject);
274 if (klass) {
275 klass->deprecated = string_to_boolean (turtle_object);
276 } else {
277 g_error ("'%s' is not a class nor a property!?", turtle_subject);
278 }
279 }
280
281 } else if (!g_strcmp0 (turtle_predicate, RDFS_LABEL)) {
282 /* Intentionaly ignored */
283 } else {
284 /* DEBUG
285 g_print ("UNHANDLED %s %s %s\n",
286 turtle_subject, turtle_predicate, turtle_object);
287 */
288 }
289
290 }
291
292 static void
293 load_description (OntologyDescription *desc,
294 const gchar *turtle_subject,
295 const gchar *turtle_predicate,
296 const gchar *turtle_object)
297 {
298 if (!g_strcmp0 (turtle_predicate, RDFS_TYPE)) {
299 g_assert (!g_strcmp0 (turtle_object, DSC_ONTOLOGY));
300 } else if (!g_strcmp0 (turtle_predicate, DSC_TITLE)) {
301 desc->title = g_strdup (turtle_object);
302 } else if (!g_strcmp0 (turtle_predicate, DSC_DESCRIPTION)) {
303 desc->description = g_strdup (turtle_object);
304 } else if (!g_strcmp0 (turtle_predicate, DSC_UPSTREAM)) {
305 desc->upstream = g_strdup (turtle_object);
306 } else if (!g_strcmp0 (turtle_predicate, DSC_AUTHOR)) {
307 desc->authors = g_list_prepend (desc->authors, g_strdup (turtle_object));
308 } else if (!g_strcmp0 (turtle_predicate, DSC_EDITOR)) {
309 desc->editors = g_list_prepend (desc->editors, g_strdup (turtle_object));
310 } else if (!g_strcmp0 (turtle_predicate, DSC_CONTRIBUTOR)) {
311 desc->contributors = g_list_prepend (desc->contributors,
312 g_strdup (turtle_object));
313 } else if (!g_strcmp0 (turtle_predicate, DSC_GITLOG)) {
314 desc->gitlog = g_strdup (turtle_object);
315 } else if (!g_strcmp0 (turtle_predicate, DSC_BASEURI)) {
316 desc->baseUrl = g_strdup (turtle_object);
317 } else if (!g_strcmp0 (turtle_predicate, DSC_RELPATH)) {
318 desc->relativePath = g_strdup (turtle_object);
319 } else if (!g_strcmp0 (turtle_predicate, DSC_LOCALPREFIX)) {
320 desc->localPrefix = g_strdup (turtle_object);
321 } else if (!g_strcmp0 (turtle_predicate, DSC_COPYRIGHT)) {
322 desc->copyright = g_strdup (turtle_object);
323 } else {
324 g_critical ("Unhandled element %s", turtle_predicate);
325 }
326 }
327
328
329 Ontology *
330 ttl_loader_load_ontology (const gchar *ttl_file)
331 {
332 Ontology *ontology;
333
334 ontology = g_new0 (Ontology, 1);
335 ontology->classes = g_hash_table_new_full (g_str_hash,
336 g_str_equal,
337 g_free,
338 (GDestroyNotify)ttl_model_class_free);
339
340 ontology->properties = g_hash_table_new_full (g_str_hash,
341 g_str_equal,
342 g_free,
343 (GDestroyNotify)ttl_model_property_free);
344
345 if (ttl_file) {
346 TrackerTurtleReader *reader;
347 GError *error = NULL;
348
349 reader = tracker_turtle_reader_new (ttl_file, NULL);
350
351 while (error == NULL && tracker_turtle_reader_next (reader, &error)) {
352 load_in_memory (ontology,
353 tracker_turtle_reader_get_subject (reader),
354 tracker_turtle_reader_get_predicate (reader),
355 tracker_turtle_reader_get_object (reader));
356 }
357
358 g_object_unref (reader);
359
360 if (error) {
361 g_message ("Turtle parse error: %s", error->message);
362 g_error_free (error);
363 }
364 } else {
365 g_warning ("Unable to open '%s'", ttl_file);
366 }
367
368 return ontology;
369 }
370
371 OntologyDescription *
372 ttl_loader_load_description (const gchar *filename)
373 {
374 OntologyDescription *desc;
375 TrackerTurtleReader *reader;
376 GError *error = NULL;
377
378 desc = ttl_model_description_new ();
379
380
381 reader = tracker_turtle_reader_new (filename, NULL);
382
383 while (error == NULL && tracker_turtle_reader_next (reader, &error)) {
384 load_description (desc,
385 tracker_turtle_reader_get_subject (reader),
386 tracker_turtle_reader_get_predicate (reader),
387 tracker_turtle_reader_get_object (reader));
388 }
389
390 g_object_unref (reader);
391
392 if (error) {
393 g_message ("Turtle parse error: %s", error->message);
394 g_error_free (error);
395 }
396
397 return desc;
398 }
399
400
401 void
402 ttl_loader_free_ontology (Ontology *ontology)
403 {
404 g_hash_table_destroy (ontology->classes);
405 g_hash_table_destroy (ontology->properties);
406 g_free (ontology);
407 }
408
409 void
410 ttl_loader_free_description (OntologyDescription *desc)
411 {
412 ttl_model_description_free (desc);
413 }