tracker-0.16.2/utils/ontology/ontology-validator.c

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 "config.h"
 21 
 22 #include <string.h>
 23 
 24 #include <glib.h>
 25 #include <glib/gstdio.h>
 26 #include <gio/gio.h>
 27 
 28 #include <libtracker-data/tracker-data.h>
 29 
 30 static gchar         *ontology_dir = NULL;
 31 
 32 static GOptionEntry   entries[] = {
 33 	{ "ontology-dir", 'o', 0, G_OPTION_ARG_FILENAME, &ontology_dir,
 34 	  "Directory containing the ontology description files (TTL FORMAT)",
 35 	  NULL
 36 	},
 37 	{ NULL }
 38 };
 39 
 40 #define RDFS_CLASS "http://www.w3.org/2000/01/rdf-schema#Class"
 41 #define RDF_PROPERTY "http://www.w3.org/1999/02/22-rdf-syntax-ns#Property"
 42 #define RDFS_SUBCLASSOF  "http://www.w3.org/2000/01/rdf-schema#subClassOf"
 43 #define RDFS_SUBPROPERTYOF  "http://www.w3.org/2000/01/rdf-schema#subPropertyOf"
 44 #define RDFS_TYPE "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
 45 #define TRACKER_NS "http://www.tracker-project.org/ontologies/tracker#Namespace"
 46 #define TRACKER_ONTO "http://www.tracker-project.org/ontologies/tracker#Ontology"
 47 #define TRACKER_PREFIX "http://www.tracker-project.org/ontologies/tracker#prefix"
 48 #define RDFS_RANGE "http://www.w3.org/2000/01/rdf-schema#range"
 49 #define RDFS_DOMAIN "http://www.w3.org/2000/01/rdf-schema#domain"
 50 #define NRL_IFP "http://www.semanticdesktop.org/ontologies/2007/08/15/nrl#InverseFunctionalProperty"
 51 
 52 static GList *unknown_items = NULL;
 53 static GList *known_items = NULL;
 54 static GList *unknown_predicates = NULL;
 55 static GList *namespaces = NULL;
 56 static GList *ontologies = NULL;
 57 
 58 static gboolean
 59 exists_or_already_reported (const gchar *item)
 60 {
 61 	if (!g_list_find_custom (known_items,
 62 	                         item,
 63 	                         (GCompareFunc) g_strcmp0)){
 64 		if (!g_list_find_custom (unknown_items,
 65 		                         item,
 66 		                         (GCompareFunc) g_strcmp0)) {
 67 			return FALSE;
 68 		}
 69 	}
 70 	return TRUE;
 71 }
 72 
 73 static void
 74 turtle_load_ontology (const gchar *turtle_subject,
 75                       const gchar *turtle_predicate,
 76                       const gchar *turtle_object)
 77 {
 78 
 79 	/* nmo:Email a rdfs:Class
 80 	 *  If rdfs:Class exists, add nmo:Email to the known_items
 81 	 **/
 82 	if (!g_strcmp0 (turtle_predicate, RDFS_TYPE)) {
 83 
 84 		if (!g_strcmp0 (turtle_object, TRACKER_NS)) {
 85 			/* Check there is no Namespace redefinition */
 86                         if (g_list_find_custom (namespaces, 
 87                                                 turtle_subject, 
 88                                                 (GCompareFunc) g_strcmp0)) {
 89                                 g_error ("Redefining Tracker:Namespace '%s'",
 90                                          turtle_subject);
 91                         } else {
 92                                 namespaces = g_list_prepend (namespaces, g_strdup (turtle_subject));
 93                         }
 94 			return;
 95 		}
 96 
 97 		if (!g_strcmp0 (turtle_object, TRACKER_ONTO)) {
 98 			/* Check there is no Ontology redefinition */
 99                         if (g_list_find_custom (ontologies, 
100                                                 turtle_subject, 
101                                                 (GCompareFunc) g_strcmp0)) {
102                                 g_error ("Redefining Tracker:Ontology '%s'",
103                                          turtle_subject);
104                         } else {
105                                 ontologies = g_list_prepend (ontologies, g_strdup (turtle_subject));
106                         }
107 			return;
108 		}
109 
110 		if (!g_strcmp0 (turtle_object, NRL_IFP)) {
111 			/* Ignore the InverseFunctionalProperty subclassing */
112 			return;
113 		}
114 
115 		/* Check the nmo:Email hasn't already be defined
116 		 *  (ignoring rdfs:Class, rdf:Property and tracker:Ontology for bootstraping reasons)
117 		 */
118 		if (exists_or_already_reported (turtle_subject)
119 		    && g_strcmp0 (turtle_subject, RDFS_CLASS)
120 		    && g_strcmp0 (turtle_subject, RDF_PROPERTY)
121                     && g_strcmp0 (turtle_subject, TRACKER_ONTO)) {
122 			g_error ("%s is already defined", turtle_subject);
123 			return;
124 		}
125 
126 		/* Check the object class is already defined */
127 		if (!exists_or_already_reported (turtle_object)) {
128 			g_error ("%s is a %s but %s is not defined",
129 			         turtle_subject, turtle_object, turtle_object);
130 		} else {
131 			/* A new type defined... if it is a predicate,
132 			 *  remove it from the maybe list!
133 			 */
134 			if (!g_strcmp0 (turtle_object, RDF_PROPERTY)) {
135 				GList *link;
136 				link = g_list_find_custom (unknown_predicates,
137 				                           turtle_subject,
138 				                           (GCompareFunc)g_strcmp0);
139 				if (link) {
140 					unknown_predicates = g_list_remove_link (unknown_predicates,
141 					                                         link);
142 				}
143 			}
144 			known_items = g_list_prepend (known_items, g_strdup (turtle_subject));
145 		}
146 		return;
147 	}
148 
149 	/*
150 	 * nmo:Message rdfs:subClassOf nie:InformationElement
151 	 *  Check nie:InformationElement is defined
152 	 */
153 	if (!g_strcmp0 (turtle_predicate, RDFS_SUBCLASSOF)
154 	    || !g_strcmp0 (turtle_predicate, RDFS_SUBPROPERTYOF)
155 	    || !g_strcmp0 (turtle_predicate, RDFS_RANGE)
156 	    || !g_strcmp0 (turtle_predicate, RDFS_DOMAIN)) {
157 		/* Check the class is already defined */
158 		if (!exists_or_already_reported (turtle_object)) {
159 			g_error ("Class %s refers to %s but it is not defined",
160 			         turtle_subject, turtle_object);
161 		}
162 		return;
163 	}
164 
165 	/*
166 	 * The predicate is not type, subclass, range, domain...
167 	 *   Put it in maybe
168 	 */
169 	if (!exists_or_already_reported (turtle_predicate)
170 	    && !g_list_find_custom (unknown_predicates,
171 	                            turtle_predicate,
172 	                            (GCompareFunc) g_strcmp0)) {
173 		unknown_predicates = g_list_prepend (unknown_predicates,
174 		                                     g_strdup (turtle_predicate));
175 	}
176 }
177 
178 static void
179 process_file (const gchar *ttl_file)
180 {
181 	TrackerTurtleReader *reader;
182 	GError *error = NULL;
183 
184 	g_print ("Processing %s\n", ttl_file);
185 
186 	reader = tracker_turtle_reader_new (ttl_file, NULL);
187 
188 	while (error == NULL && tracker_turtle_reader_next (reader, &error)) {
189 		turtle_load_ontology (tracker_turtle_reader_get_subject (reader),
190 		                      tracker_turtle_reader_get_predicate (reader),
191 		                      tracker_turtle_reader_get_object (reader));
192 	}
193 
194 	g_object_unref (reader);
195 
196 	if (error) {
197 		g_message ("Turtle parse error: %s", error->message);
198 		g_error_free (error);
199 	}
200 }
201 
202 static void
203 load_ontology_files (const gchar *services_dir)
204 {
205 	GList       *files = NULL;
206 	GDir        *services;
207 	const gchar *conf_file;
208 	GFile       *f;
209 	gchar       *dir_uri, *fullpath;
210 
211 	f = g_file_new_for_path (services_dir);
212 	dir_uri = g_file_get_path (f);
213 
214 	g_print ("dir_uri %s\n", dir_uri);
215 	services = g_dir_open (dir_uri, 0, NULL);
216 
217 	conf_file = g_dir_read_name (services);
218 
219 	while (conf_file) {
220 
221 		if (!g_str_has_suffix (conf_file, "ontology")) {
222 			conf_file = g_dir_read_name (services);
223 			continue;
224 		}
225 
226 		fullpath = g_build_filename (dir_uri, conf_file, NULL);
227 		files = g_list_insert_sorted (files, fullpath, (GCompareFunc) g_strcmp0);
228 		conf_file = g_dir_read_name (services);
229 	}
230 
231 	g_dir_close (services);
232 
233 	//process_file (fullpath, turtle_load_ontology, NULL);
234 	g_list_foreach (files, (GFunc) process_file, turtle_load_ontology);
235 
236 	g_list_foreach (files, (GFunc) g_free, NULL);
237 	g_object_unref (f);
238 	g_free (dir_uri);
239 }
240 
241 static void
242 load_basic_classes ()
243 {
244 	known_items = g_list_prepend (known_items, g_strdup (RDFS_CLASS));
245 	known_items = g_list_prepend (known_items, g_strdup (RDF_PROPERTY));
246         known_items = g_list_prepend (known_items, g_strdup (TRACKER_ONTO));
247 }
248 
249 static void
250 clean_lists ()
251 {
252         if (unknown_items) {
253                 g_list_foreach (unknown_items, (GFunc)g_free, NULL);
254                 unknown_items = NULL;
255         }
256 
257         if (known_items) {
258                 g_list_foreach (known_items, (GFunc)g_free, NULL);
259                 known_items = NULL;
260         }
261 
262         if (unknown_predicates) {
263                 g_list_foreach (unknown_predicates, (GFunc)g_free, NULL);
264                 unknown_predicates = NULL;
265         }
266 
267         if (ontologies) {
268                 g_list_foreach (ontologies, (GFunc)g_free, NULL);
269                 ontologies = NULL;
270         }
271 }
272 
273 gint
274 main (gint argc, gchar **argv)
275 {
276 	GOptionContext *context;
277 	GList *it;
278 
279 	/* Translators: this messagge will apper immediately after the  */
280 	/* usage string - Usage: COMMAND [OPTION]... <THIS_MESSAGE>     */
281 	context = g_option_context_new ("- Validate the ontology consistency");
282 
283 	/* Translators: this message will appear after the usage string */
284 	/* and before the list of options.                              */
285 	g_option_context_add_main_entries (context, entries, NULL);
286 	g_option_context_parse (context, &argc, &argv, NULL);
287 
288 	if (!ontology_dir) {
289 		gchar *help;
290 
291 		g_printerr ("%s\n\n",
292 		            "Ontology directory is mandatory");
293 
294 		help = g_option_context_get_help (context, TRUE, NULL);
295 		g_option_context_free (context);
296 		g_printerr ("%s", help);
297 		g_free (help);
298 
299 		return -1;
300 	}
301 
302 	load_basic_classes ();
303 	//"/home/ivan/devel/codethink/tracker-ssh/data/services"
304 	load_ontology_files (ontology_dir);
305 
306 
307 	for (it = unknown_predicates; it != NULL; it = it->next) {
308 		g_error ("Predicate '%s' is used in the ontology, but it is not defined\n",
309 		         (gchar *)it->data);
310 	}
311 
312         clean_lists ();
313 
314 	return 0;
315 }