[tracker] Add class signals



commit 1a8e11987df109705985b7f446f8ad22a6b3663f
Author: Philip Van Hoof <philip codeminded be>
Date:   Thu Apr 9 18:06:13 2009 +0200

    Add class signals
---
 data/dbus/Makefile.am                       |    3 +-
 data/dbus/tracker-indexer.xml               |    3 +
 data/dbus/tracker-resources-class.xml       |   25 +++
 data/ontologies/33-nfo.ontology             |    4 +
 data/ontologies/34-nmo.ontology             |    1 +
 data/ontologies/90-tracker.ontology         |    4 +
 src/libtracker-common/tracker-dbus.h        |    8 +
 src/libtracker-data/tracker-data-query.c    |   42 +++++
 src/libtracker-data/tracker-data-query.h    |    2 +
 src/libtracker-data/tracker-data-update.c   |   64 ++++++++
 src/libtracker-data/tracker-data-update.h   |   15 ++
 src/tracker-indexer/Makefile.am             |    4 +-
 src/tracker-indexer/tracker-events.c        |  220 +++++++++++++++++++++++++
 src/tracker-indexer/tracker-events.h        |   45 +++++
 src/tracker-indexer/tracker-indexer.c       |   86 ++++++++++
 src/tracker-indexer/tracker-indexer.h       |    6 +
 src/tracker-indexer/tracker-main.c          |    7 +-
 src/trackerd/Makefile.am                    |    5 +-
 src/trackerd/tracker-dbus.c                 |   81 +++++++++-
 src/trackerd/tracker-resource-class.c       |  232 +++++++++++++++++++++++++++
 src/trackerd/tracker-resource-class.h       |   65 ++++++++
 src/trackerd/tracker-resources.c            |  106 ++++++++++++
 src/trackerd/tracker-resources.h            |    6 +
 tests/tracker-indexer/Makefile.am           |   16 ++-
 tests/tracker-indexer/tracker-events-test.c |  187 +++++++++++++++++++++
 25 files changed, 1231 insertions(+), 6 deletions(-)

diff --git a/data/dbus/Makefile.am b/data/dbus/Makefile.am
index ae6ae5f..f4fc891 100644
--- a/data/dbus/Makefile.am
+++ b/data/dbus/Makefile.am
@@ -8,7 +8,8 @@ config_DATA =						\
 	tracker-resources.xml				\
 	tracker-search.xml				\
 	tracker-indexer.xml				\
-	tracker-extract.xml
+	tracker-extract.xml				\
+	tracker-resources-class.xml
 
 # Services
 servicedir = $(DBUS_SERVICES_DIR)
diff --git a/data/dbus/tracker-indexer.xml b/data/dbus/tracker-indexer.xml
index 0c26ef9..1594783 100644
--- a/data/dbus/tracker-indexer.xml
+++ b/data/dbus/tracker-indexer.xml
@@ -117,5 +117,8 @@
       <arg type="s" name="reason" />
       <arg type="b" name="requires_reindexing" />
     </signal>
+    <signal name="EventHappened">
+      <arg type="a(ssi)" name="events" />
+    </signal>
   </interface>
 </node>
diff --git a/data/dbus/tracker-resources-class.xml b/data/dbus/tracker-resources-class.xml
new file mode 100644
index 0000000..c595933
--- /dev/null
+++ b/data/dbus/tracker-resources-class.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<node name="/">
+  <interface name="org.freedesktop.Tracker.Resources.Class"> 
+
+    <!-- Signal for changed subjects -->
+
+    <signal name="SubjectsChanged">
+     <arg type="as" name="subject" />
+    </signal>
+
+    <!-- Signal for added subjects -->
+
+    <signal name="SubjectsAdded">
+      <arg type="as" name="subject" />
+    </signal>
+
+    <!-- Signal for removed subjects -->
+
+    <signal name="SubjectsRemoved">
+      <arg type="as" name="subject" />
+   </signal>
+
+  </interface>
+</node>
diff --git a/data/ontologies/33-nfo.ontology b/data/ontologies/33-nfo.ontology
index 28ec288..af56503 100644
--- a/data/ontologies/33-nfo.ontology
+++ b/data/ontologies/33-nfo.ontology
@@ -39,6 +39,7 @@ nfo:Visual a rdfs:Class ;
 nfo:Image a rdfs:Class ;
 	rdfs:label "Image" ;
 	rdfs:comment "A file containing an image." ;
+	tracker:notify true ;
 	rdfs:subClassOf nfo:Visual .
 
 nfo:RasterImage a rdfs:Class ;
@@ -68,6 +69,7 @@ nfo:VectorImage a rdfs:Class ;
 nfo:Audio a rdfs:Class ;
 	rdfs:label "Audio" ;
 	rdfs:comment "A file containing audio content" ;
+	tracker:notify true ;
 	rdfs:subClassOf nfo:Media .
 
 nfo:CompressionType a rdfs:Class ;
@@ -233,6 +235,7 @@ nfo:Cursor a rdfs:Class ;
 nfo:Bookmark a rdfs:Class ;
 	rdfs:label "Bookmark" ;
 	rdfs:comment "['A bookmark of a webbrowser. Use nie:title for the name/label', 'nie:contentCreated to represent the date when the user added the bookmark', 'and nie:contentLastModified for modifications. nfo:bookmarks to store the link.']" ;
+	tracker:notify true ;
 	rdfs:subClassOf nie:InformationElement .
 
 nfo:DeletedResource a rdfs:Class ;
@@ -248,6 +251,7 @@ nfo:Website a rdfs:Class ;
 nfo:WebHistory a rdfs:Class ;
 	rdfs:label "Web History" ;
         rdfs:comment "A web history entry" ;
+	tracker:notify true ;
         rdfs:subClassOf nie:InformationElement .
 
 nfo:count a rdf:Property ;
diff --git a/data/ontologies/34-nmo.ontology b/data/ontologies/34-nmo.ontology
index c1e457f..a173272 100644
--- a/data/ontologies/34-nmo.ontology
+++ b/data/ontologies/34-nmo.ontology
@@ -61,6 +61,7 @@ nmo:FeedChannel a rdfs:Class ;
 	rdfs:subClassOf nmo:CommunicationChannel .
 
 nmo:FeedMessage a rdfs:Class ;
+	tracker:notify true ;
 	rdfs:subClassOf nmo:Message .
 
 nmo:VOIPCall a rdfs:Class ;
diff --git a/data/ontologies/90-tracker.ontology b/data/ontologies/90-tracker.ontology
index 14ca0c9..0144dc0 100644
--- a/data/ontologies/90-tracker.ontology
+++ b/data/ontologies/90-tracker.ontology
@@ -14,6 +14,10 @@ tracker:tagRelatedTo a rdf:Property ;
 	rdfs:domain nao:Tag ;
 	rdfs:range rdfs:Class .
 
+tracker:notify a rdf:Property ;
+	rdfs:domain rdfs:Class ;
+	rdfs:range xsd:boolean .
+
 tracker:Volume a rdfs:Class ;
 	rdfs:label "Storage media" ;
 	rdfs:subClassOf nie:DataSource .
diff --git a/src/libtracker-common/tracker-dbus.h b/src/libtracker-common/tracker-dbus.h
index 8f44f30..b2fcd1d 100644
--- a/src/libtracker-common/tracker-dbus.h
+++ b/src/libtracker-common/tracker-dbus.h
@@ -72,6 +72,14 @@ G_BEGIN_DECLS
 		};							\
 	} G_STMT_END
 
+typedef enum {
+	TRACKER_DBUS_EVENTS_TYPE_ADD,
+	TRACKER_DBUS_EVENTS_TYPE_UPDATE,
+	TRACKER_DBUS_EVENTS_TYPE_DELETE
+} TrackerDBusEventsType;
+
+#define TRACKER_TYPE_EVENT_ARRAY	dbus_g_type_get_collection ("GPtrArray", dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INVALID))
+
 typedef struct TrackerDBusRequestHandler TrackerDBusRequestHandler;
 
 typedef void (*TrackerDBusRequestFunc)	 (guint    request_id,
diff --git a/src/libtracker-data/tracker-data-query.c b/src/libtracker-data/tracker-data-query.c
index 7f08bc8..cc79296 100644
--- a/src/libtracker-data/tracker-data-query.c
+++ b/src/libtracker-data/tracker-data-query.c
@@ -210,6 +210,48 @@ tracker_data_query_all_metadata (guint32 resource_id)
 
 }
 
+
+GPtrArray*
+tracker_data_query_rdf_type (guint32 id)
+{
+	TrackerDBResultSet *result_set;
+	TrackerDBInterface *iface;
+	TrackerDBStatement *stmt;
+	GPtrArray *ret = NULL;
+
+	iface = tracker_db_manager_get_db_interface ();
+
+	stmt = tracker_db_interface_create_statement (iface,
+			"SELECT \"rdfs:Resource\".\"Uri\" "
+			"FROM \"rdfs:Resource_rdf:type\" "
+			"INNER JOIN \"rdfs:Resource\" "
+			"ON \"rdfs:Resource_rdf:type\".\"rdf:type\" = \"rdfs:Resource\".\"ID\" "
+			"WHERE \"rdfs:Resource_rdf:type\".\"ID\" = ?");
+
+	tracker_db_statement_bind_int (stmt, 0, id);
+	result_set = tracker_db_statement_execute (stmt, NULL);
+	g_object_unref (stmt);
+
+	if (result_set) {
+		guint rows;
+
+		rows = tracker_db_result_set_get_n_rows (result_set);
+		ret = g_ptr_array_sized_new (rows);
+		do {
+			gchar *uri;
+
+			tracker_db_result_set_get (result_set, 0, &uri, -1);
+
+			g_ptr_array_add (ret, uri);
+
+		} while (tracker_db_result_set_iter_next (result_set));
+
+		g_object_unref (result_set);
+	}
+
+	return ret;
+}
+
 guint32
 tracker_data_query_resource_id (const gchar	   *uri)
 {
diff --git a/src/libtracker-data/tracker-data-query.h b/src/libtracker-data/tracker-data-query.h
index 6743f89..0d56441 100644
--- a/src/libtracker-data/tracker-data-query.h
+++ b/src/libtracker-data/tracker-data-query.h
@@ -60,6 +60,8 @@ guint32              tracker_data_query_resource_id           (const gchar
 TrackerDBResultSet *tracker_data_query_sparql			(const gchar       *query,
 								 GError	          **error);
 
+GPtrArray*          tracker_data_query_rdf_type               (guint32              id);
+
 G_END_DECLS
 
 #endif /* __TRACKER_DATA_QUERY_H__ */
diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c
index 7c4e8c8..ec6b33f 100644
--- a/src/libtracker-data/tracker-data-update.c
+++ b/src/libtracker-data/tracker-data-update.c
@@ -52,6 +52,7 @@ struct _TrackerDataUpdateBuffer {
 	gchar *subject;
 	guint32 id;
 	GHashTable *tables;
+	GPtrArray *types;
 };
 
 struct _TrackerDataUpdateBufferProperty {
@@ -85,6 +86,37 @@ static gboolean auto_commit = TRUE;
 static TrackerDataUpdateBuffer update_buffer;
 static TrackerDataBlankBuffer blank_buffer;
 
+static TrackerStatementCallback insert_callback = NULL;
+static gpointer insert_data;
+static TrackerStatementCallback delete_callback = NULL;
+static gpointer delete_data;
+static TrackerCommitCallback commit_callback = NULL;
+static gpointer commit_data;
+
+void 
+tracker_data_set_commit_statement_callback (TrackerCommitCallback    callback,
+					    gpointer                 user_data)
+{
+	commit_callback = callback;
+	commit_data = user_data;
+}
+
+void
+tracker_data_set_insert_statement_callback (TrackerStatementCallback callback,
+					    gpointer                 user_data)
+{
+	insert_callback = callback;
+	insert_data = user_data;
+}
+
+void 
+tracker_data_set_delete_statement_callback (TrackerStatementCallback callback,
+					    gpointer                 user_data)
+{
+	delete_callback = callback;
+	delete_data = user_data;
+}
+
 static guint32
 tracker_data_update_get_new_service_id (TrackerDBInterface *iface)
 {
@@ -348,6 +380,12 @@ tracker_data_update_buffer_flush (void)
 	g_hash_table_remove_all (update_buffer.tables);
 	g_free (update_buffer.subject);
 	update_buffer.subject = NULL;
+
+	if (update_buffer.types) {
+		g_ptr_array_foreach (update_buffer.types, (GFunc) g_free, NULL);
+		g_ptr_array_free (update_buffer.types, TRUE);
+		update_buffer.types = NULL;
+	}
 }
 
 static void
@@ -794,6 +832,7 @@ tracker_data_delete_statement (const gchar            *subject,
 	TrackerClass       *class;
 	TrackerProperty    *field;
 	gint		    subject_id;
+	GPtrArray          *types;
 
 	if (auto_commit) {
 		tracker_data_begin_implicit_transaction ();
@@ -811,6 +850,8 @@ tracker_data_delete_statement (const gchar            *subject,
 		return;
 	}
 
+	types = tracker_data_query_rdf_type (subject_id);
+
 	if (object && g_strcmp0 (predicate, RDF_PREFIX "type") == 0) {
 		class = tracker_ontology_get_class_by_uri (object);
 		if (class != NULL) {
@@ -910,6 +951,15 @@ tracker_data_delete_statement (const gchar            *subject,
 		}
 	}
 
+	if (delete_callback) {
+		delete_callback (subject, predicate, object, types, delete_data);
+	}
+
+	if (types) {
+		g_ptr_array_foreach (types, (GFunc) g_free, NULL);
+		g_ptr_array_free (types, TRUE);
+	}
+
 	if (auto_commit) {
 		tracker_data_commit_transaction ();
 	}
@@ -997,6 +1047,7 @@ tracker_data_insert_statement (const gchar            *subject,
 		/* subject not yet in cache, retrieve or create ID */
 		update_buffer.subject = g_strdup (subject);
 		update_buffer.id = ensure_resource_id (update_buffer.subject);
+		update_buffer.types = tracker_data_query_rdf_type (update_buffer.id);
 
 		g_value_set_int64 (&gvalue, (gint64) time (NULL));
 		cache_insert_value ("rdfs:Resource", "Modified", &gvalue, FALSE);
@@ -1008,6 +1059,11 @@ tracker_data_insert_statement (const gchar            *subject,
 		service = tracker_ontology_get_class_by_uri (object);
 		if (service != NULL) {
 			cache_create_service_decomposed (service);
+
+			if (!update_buffer.types)
+				update_buffer.types = g_ptr_array_new ();
+			g_ptr_array_add (update_buffer.types, g_strdup (object));
+
 		} else {
 			g_warning ("Class '%s' not found in the ontology", object);
 		}
@@ -1044,9 +1100,14 @@ tracker_data_insert_statement (const gchar            *subject,
 		}
 	}
 
+	if (insert_callback) {
+		insert_callback (subject, predicate, object, update_buffer.types, insert_data);
+	}
+
 	if (auto_commit) {
 		tracker_data_commit_transaction ();
 	}
+
 }
 
 void
@@ -1390,6 +1451,9 @@ tracker_data_commit_transaction (void)
 
 	g_hash_table_unref (update_buffer.resource_cache);
 
+	if (commit_callback)
+		commit_callback (commit_data);
+
 	auto_commit = TRUE;
 }
 
diff --git a/src/libtracker-data/tracker-data-update.h b/src/libtracker-data/tracker-data-update.h
index 14e1639..2f1bcf0 100644
--- a/src/libtracker-data/tracker-data-update.h
+++ b/src/libtracker-data/tracker-data-update.h
@@ -61,6 +61,21 @@ void tracker_data_update_disable_volume                 (const gchar         *ud
 void tracker_data_update_disable_all_volumes            (void);
 void tracker_data_update_reset_volume                   (const gchar         *uri);
 
+/* Calling back */
+typedef void (*TrackerStatementCallback)                (const gchar *subject, 
+							 const gchar *predicate, 
+							 const gchar *object,
+							 GPtrArray   *rdf_types,
+							 gpointer user_data);
+typedef void (*TrackerCommitCallback)                   (gpointer user_data);
+
+void tracker_data_set_insert_statement_callback         (TrackerStatementCallback callback,
+							 gpointer                 user_data);
+void tracker_data_set_delete_statement_callback         (TrackerStatementCallback callback,
+							 gpointer                 user_data);
+void tracker_data_set_commit_statement_callback         (TrackerCommitCallback    callback,
+							 gpointer                 user_data);
+
 G_END_DECLS
 
 #endif /* __TRACKER_DATA_UPDATE_H__ */
diff --git a/src/tracker-indexer/Makefile.am b/src/tracker-indexer/Makefile.am
index c4a3a47..99dd9c7 100644
--- a/src/tracker-indexer/Makefile.am
+++ b/src/tracker-indexer/Makefile.am
@@ -54,7 +54,9 @@ tracker_indexer_SOURCES =						\
 	tracker-removable-device.c					\
 	tracker-removable-device.h					\
 	tracker-push.c							\
-	tracker-push.h
+	tracker-push.h							\
+	tracker-events.c						\
+	tracker-events.h
 
 tracker_indexer_LDADD =							\
 	$(plugin_libs)							\
diff --git a/src/tracker-indexer/tracker-events.c b/src/tracker-indexer/tracker-events.c
new file mode 100644
index 0000000..1c2df13
--- /dev/null
+++ b/src/tracker-indexer/tracker-events.c
@@ -0,0 +1,220 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Authors:
+ *  Philip Van Hoof <philip codeminded be>
+ */
+
+#include "config.h"
+
+#include <libtracker-common/tracker-ontology.h>
+
+#include "tracker-events.h"
+
+
+typedef struct {
+	GPtrArray *allowances;
+	GPtrArray *events;
+} EventsPrivate;
+
+static GStaticPrivate private_key = G_STATIC_PRIVATE_INIT;
+
+static void 
+tracker_events_add_allow (const gchar *rdf_class)
+{
+	EventsPrivate *private;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	g_ptr_array_add (private->allowances, g_strdup (rdf_class));
+}
+
+static gboolean
+is_allowed (EventsPrivate *private, const gchar *rdf_class)
+{
+	guint i;
+	gboolean found = FALSE;
+
+	for (i = 0; i < private->allowances->len;  i++) {
+		if (g_strcmp0 (rdf_class, private->allowances->pdata[i]) == 0) {
+			found = TRUE;
+			break;
+		}
+	}
+
+	return found;
+}
+
+typedef struct {
+	const gchar *uri;
+	TrackerDBusEventsType type;
+} PreparableEvent;
+
+static void 
+prepare_event_for_rdf_types (gpointer data, gpointer user_data)
+{
+	const gchar *rdf_class = data;
+	PreparableEvent *info = user_data;
+	const gchar *uri = info->uri;
+	TrackerDBusEventsType type = info->type;
+
+	EventsPrivate *private;
+	GValueArray *event;
+	GValue uri_value = { 0 , };
+	GValue rdfclass_value = { 0 , };
+	GValue type_value = { 0 , };
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	if (!is_allowed (private, rdf_class))
+		return;
+
+	if (!private->events) {
+		private->events = g_ptr_array_new ();
+	}
+
+	g_value_init (&uri_value, G_TYPE_STRING);
+	g_value_init (&rdfclass_value, G_TYPE_STRING);
+	g_value_init (&type_value, G_TYPE_INT);
+
+	event = g_value_array_new (3);
+
+	g_value_set_string (&uri_value, uri);
+	g_value_set_string (&rdfclass_value, rdf_class);
+	g_value_set_int (&type_value, type);
+
+	g_value_array_append (event, &uri_value);
+	g_value_array_append (event, &rdfclass_value);
+	g_value_array_append (event, &type_value);
+
+	g_ptr_array_add (private->events, event);
+
+	g_value_unset (&uri_value);
+	g_value_unset (&rdfclass_value);
+	g_value_unset (&type_value);
+}
+
+void 
+tracker_events_insert (const gchar *uri, 
+		       const gchar *object, 
+		       GPtrArray *rdf_types, 
+		       TrackerDBusEventsType type)
+{
+	PreparableEvent info;
+
+	info.uri = uri;
+	info.type = type;
+
+	if (rdf_types && type == TRACKER_DBUS_EVENTS_TYPE_UPDATE) {
+		/* object is not very important for updates (we don't expose
+		 * the value being set to the user's DBus API in trackerd) */
+		g_ptr_array_foreach (rdf_types, prepare_event_for_rdf_types, &info);
+	} else if (type == TRACKER_DBUS_EVENTS_TYPE_UPDATE) {
+		/* In this case we had an INSERT for a resource that didn't exist 
+		 * yet, but it was not the rdf:type predicate being inserted */
+		prepare_event_for_rdf_types ((gpointer) TRACKER_RDFS_PREFIX "Resource", &info);
+	} else {
+		/* In case of delete and create, object is the rdf:type */
+		prepare_event_for_rdf_types ((gpointer) object, &info);
+	}
+}
+
+void 
+tracker_events_reset (void)
+{
+	EventsPrivate *private;
+	guint i;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	if (private->events) {
+		for (i = 0; i < private->events->len; i++) {
+			g_value_array_free (private->events->pdata[i]);
+		}
+		g_ptr_array_free (private->events, TRUE);
+
+		private->events = NULL;
+	}
+}
+
+GPtrArray *
+tracker_events_get_pending (void)
+{
+	EventsPrivate *private;
+
+	private = g_static_private_get (&private_key);
+	g_return_val_if_fail (private != NULL, NULL);
+
+	return private->events;
+}
+
+static void
+free_private (EventsPrivate *private)
+{
+	g_ptr_array_foreach (private->allowances, (GFunc)g_free, NULL);
+	g_ptr_array_free (private->allowances, TRUE);
+	g_free (private);
+}
+
+void 
+tracker_events_init (TrackerNotifyClassGetter callback)
+{
+	EventsPrivate *private;
+	GStrv          classes_to_signal;
+	gint           i, count;
+
+	private = g_new0 (EventsPrivate, 1);
+
+	g_static_private_set (&private_key,
+			      private,
+			      (GDestroyNotify) free_private);
+
+	private->allowances = g_ptr_array_new ();
+	private->events = NULL;
+
+	if (!callback) {
+		return;
+	}
+
+	classes_to_signal = (*callback)();
+	count = g_strv_length (classes_to_signal);
+	for (i = 0; i < count; i++) {
+		tracker_events_add_allow (classes_to_signal[i]);
+	}
+
+	g_strfreev (classes_to_signal);
+}
+
+void 
+tracker_events_shutdown (void)
+{
+	EventsPrivate *private;
+
+	private = g_static_private_get (&private_key);
+	if (private != NULL) {
+		/* Shutdown with pending events = ERROR */
+		g_return_if_fail (private->events == NULL);
+		g_static_private_set (&private_key, NULL, NULL);
+	} else {
+		g_warning ("tracker_events already shutdown");
+	}
+}
diff --git a/src/tracker-indexer/tracker-events.h b/src/tracker-indexer/tracker-events.h
new file mode 100644
index 0000000..9c0197a
--- /dev/null
+++ b/src/tracker-indexer/tracker-events.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Authors:
+ *  Philip Van Hoof <philip codeminded be>
+ */
+
+#ifndef __TRACKER_INDEXER_EVENTS_H__
+#define __TRACKER_INDEXER_EVENTS_H__
+
+#include <libtracker-common/tracker-dbus.h>
+
+G_BEGIN_DECLS
+
+typedef GStrv (*TrackerNotifyClassGetter) (void);
+
+void       tracker_events_init        (TrackerNotifyClassGetter callback);
+void       tracker_events_shutdown    (void);
+void       tracker_events_insert      (const gchar           *uri,
+				       const gchar           *object,
+				       GPtrArray             *rdf_types,
+				       TrackerDBusEventsType  type);
+GPtrArray *tracker_events_get_pending (void);
+void       tracker_events_reset       (void);
+
+
+G_END_DECLS
+
+#endif /* __TRACKER_INDEXER_PUSH_H__ */
diff --git a/src/tracker-indexer/tracker-indexer.c b/src/tracker-indexer/tracker-indexer.c
index 5153325..7d68960 100644
--- a/src/tracker-indexer/tracker-indexer.c
+++ b/src/tracker-indexer/tracker-indexer.c
@@ -70,6 +70,7 @@
 #include <libtracker-common/tracker-thumbnailer.h>
 
 #include <libtracker-db/tracker-db-index-manager.h>
+#include <libtracker-db/tracker-db-dbus.h>
 
 #include <libtracker-data/tracker-data-manager.h>
 #include <libtracker-data/tracker-data-query.h>
@@ -83,6 +84,7 @@
 #include "tracker-marshal.h"
 #include "tracker-module-metadata-private.h"
 #include "tracker-removable-device.h"
+#include "tracker-events.h"
 
 #define TRACKER_INDEXER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRACKER_TYPE_INDEXER, TrackerIndexerPrivate))
 
@@ -201,6 +203,7 @@ enum {
 	PAUSED,
 	CONTINUED,
 	INDEXING_ERROR,
+	EVENT_HAPPENED,
 	LAST_SIGNAL
 };
 
@@ -226,6 +229,49 @@ static guint signals[LAST_SIGNAL] = { 0, };
 
 G_DEFINE_TYPE (TrackerIndexer, tracker_indexer, G_TYPE_OBJECT)
 
+
+static void
+on_statements_committed (gpointer user_data)
+{
+	GPtrArray *events;
+	TrackerIndexer *indexer = user_data;
+
+	events = tracker_events_get_pending ();
+	if (events) {
+		tracker_indexer_make_event_happen (indexer, events);
+	}
+	tracker_events_reset ();
+}
+
+static void
+on_statement_inserted (const gchar *subject, 
+		       const gchar *predicate, 
+		       const gchar *object, 
+		       GPtrArray   *rdf_types,
+		       gpointer user_data)
+{
+	if (g_strcmp0 (predicate, RDF_PREFIX "type") == 0) {
+		tracker_events_insert (subject, object, rdf_types, TRACKER_DBUS_EVENTS_TYPE_ADD);
+	} else {
+		tracker_events_insert (subject, object, rdf_types, TRACKER_DBUS_EVENTS_TYPE_UPDATE);
+	}
+}
+
+static void
+on_statement_deleted (const gchar *subject, 
+		      const gchar *predicate, 
+		      const gchar *object, 
+		      GPtrArray   *rdf_types,
+		      gpointer user_data)
+{
+	if (g_strcmp0 (predicate, RDF_PREFIX "type") == 0) {
+		tracker_events_insert (subject, object, rdf_types, TRACKER_DBUS_EVENTS_TYPE_DELETE);
+	} else {
+		tracker_events_insert (subject, object, rdf_types, TRACKER_DBUS_EVENTS_TYPE_UPDATE);
+	}
+}
+
+
 static PathInfo *
 path_info_new (TrackerIndexerModule *module,
 	       GFile                *file,
@@ -770,6 +816,17 @@ tracker_indexer_class_init (TrackerIndexerClass *class)
 			      G_TYPE_NONE,
 			      2, G_TYPE_STRING, G_TYPE_BOOLEAN);
 
+	signals[EVENT_HAPPENED] =
+		g_signal_new ("event-happened",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (TrackerIndexerClass, event_happened),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__BOXED,
+			      G_TYPE_NONE,
+			      1,
+			      TRACKER_TYPE_EVENT_ARRAY);
+
 	g_object_class_install_property (object_class,
 					 PROP_RUNNING,
 					 g_param_spec_boolean ("running",
@@ -781,6 +838,13 @@ tracker_indexer_class_init (TrackerIndexerClass *class)
 	g_type_class_add_private (object_class, sizeof (TrackerIndexerPrivate));
 }
 
+void
+tracker_indexer_make_event_happen   (TrackerIndexer         *indexer,
+				     GPtrArray              *events)
+{
+	g_signal_emit (indexer, signals[EVENT_HAPPENED], 0, events);
+}
+
 static void
 check_started (TrackerIndexer *indexer)
 {
@@ -950,6 +1014,10 @@ tracker_indexer_init (TrackerIndexer *indexer)
 
 	priv = indexer->private = TRACKER_INDEXER_GET_PRIVATE (indexer);
 
+	tracker_data_set_insert_statement_callback (on_statement_inserted, indexer);
+	tracker_data_set_delete_statement_callback (on_statement_deleted, indexer);
+	tracker_data_set_commit_statement_callback (on_statements_committed, indexer);
+
 	/* NOTE: We set this to stopped because it is likely the
 	 * daemon sends a request for something other than to check
 	 * files initially and we don't want to signal finished and
@@ -1903,6 +1971,24 @@ process_func (gpointer data)
 	return TRUE;
 }
 
+GStrv
+tracker_indexer_get_notifiable_classes (void)
+{
+	TrackerDBResultSet *result_set;
+	GStrv               classes_to_signal = NULL;
+
+	result_set = tracker_data_query_sparql ("SELECT ?class WHERE { ?class tracker:notify true }", NULL);
+
+	if (result_set) {
+		guint count = 0;
+
+		classes_to_signal = tracker_dbus_query_result_to_strv (result_set, 0, &count);
+		g_object_unref (result_set);
+	}
+
+	return classes_to_signal;
+}
+
 TrackerIndexer *
 tracker_indexer_new (void)
 {
diff --git a/src/tracker-indexer/tracker-indexer.h b/src/tracker-indexer/tracker-indexer.h
index 11740b2..fd13613 100644
--- a/src/tracker-indexer/tracker-indexer.h
+++ b/src/tracker-indexer/tracker-indexer.h
@@ -76,6 +76,8 @@ struct TrackerIndexerClass {
 	void (*indexing_error)  (TrackerIndexer *indexer,
 				 const gchar    *reason,
 				 gboolean        requires_reindex);
+	void (*event_happened)	(TrackerIndexer *indexer,
+				 GPtrArray      *events);
 };
 
 GType		tracker_indexer_get_type	    (void) G_GNUC_CONST;
@@ -91,6 +93,8 @@ void            tracker_indexer_process_modules     (TrackerIndexer         *ind
 						     gchar                 **modules);
 void		tracker_indexer_transaction_commit  (TrackerIndexer         *indexer);
 void		tracker_indexer_transaction_open    (TrackerIndexer         *indexer);
+void		tracker_indexer_make_event_happen   (TrackerIndexer         *indexer,
+						     GPtrArray              *events);
 
 /* DBus methods */
 void            tracker_indexer_pause               (TrackerIndexer         *indexer,
@@ -161,6 +165,8 @@ void            tracker_indexer_shutdown            (TrackerIndexer         *ind
 						     DBusGMethodInvocation  *context,
 						     GError                **error);
 
+GStrv           tracker_indexer_get_notifiable_classes  (void);
+
 G_END_DECLS
 
 #endif /* __TRACKER_INDEXER_H__ */
diff --git a/src/tracker-indexer/tracker-main.c b/src/tracker-indexer/tracker-main.c
index 7ea7588..6da6005 100644
--- a/src/tracker-indexer/tracker-main.c
+++ b/src/tracker-indexer/tracker-main.c
@@ -45,15 +45,18 @@
 
 #include <libtracker-db/tracker-db-manager.h>
 #include <libtracker-db/tracker-db-index-manager.h>
+#include <libtracker-db/tracker-db-dbus.h>
 
 #include <libtracker-data/tracker-data-manager.h>
 #include <libtracker-data/tracker-data-update.h>
+#include <libtracker-data/tracker-data-query.h>
 #include <libtracker-data/tracker-turtle.h>
 
 #include "tracker-dbus.h"
+#include "tracker-events.h"
 #include "tracker-indexer.h"
-#include "tracker-push.h"
 #include "tracker-indexer-glue.h"
+#include "tracker-push.h"
 
 #define ABOUT								  \
 	"Tracker " PACKAGE_VERSION "\n"
@@ -413,6 +416,7 @@ main (gint argc, gchar *argv[])
                 tracker_indexer_process_modules (indexer, modules);
         }
 
+	tracker_events_init (tracker_indexer_get_notifiable_classes);
 	tracker_push_init (config, indexer);
 
 	tracker_turtle_init ();
@@ -437,6 +441,7 @@ main (gint argc, gchar *argv[])
 	g_object_unref (language);
 
 	tracker_push_shutdown ();
+	tracker_events_shutdown ();
 
 	tracker_thumbnailer_shutdown ();
 	tracker_dbus_shutdown ();
diff --git a/src/trackerd/Makefile.am b/src/trackerd/Makefile.am
index 97ceed2..5bd9fa5 100644
--- a/src/trackerd/Makefile.am
+++ b/src/trackerd/Makefile.am
@@ -60,7 +60,9 @@ trackerd_SOURCES =							\
 	tracker-push.c							\
 	tracker-push.h							\
 	tracker-push-registrar.c					\
-	tracker-push-registrar.h
+	tracker-push-registrar.h					\
+	tracker-resource-class.c					\
+	tracker-resource-class.h
 
 if OS_WIN32
 trackerd_win_libs = -lws2_32 -lkernel32
@@ -106,6 +108,7 @@ dbus_sources = 								\
 	tracker-daemon-glue.h						\
 	tracker-resources-glue.h					\
 	tracker-search-glue.h						\
+	tracker-resources-class-glue.h					\
 	tracker-indexer-client.h
 
 %-glue.h: $(top_srcdir)/data/dbus/%.xml
diff --git a/src/trackerd/tracker-dbus.c b/src/trackerd/tracker-dbus.c
index e85c169..8d536d0 100644
--- a/src/trackerd/tracker-dbus.c
+++ b/src/trackerd/tracker-dbus.c
@@ -25,16 +25,21 @@
 #include <libtracker-common/tracker-dbus.h>
 #include <libtracker-common/tracker-log.h>
 #include <libtracker-common/tracker-utils.h>
+#include <libtracker-common/tracker-ontology.h>
 
+#include <libtracker-db/tracker-db-dbus.h>
 #include <libtracker-db/tracker-db-manager.h>
 
 #include <libtracker-data/tracker-data-manager.h>
+#include <libtracker-data/tracker-data-query.h>
 
 #include "tracker-dbus.h"
 #include "tracker-daemon.h"
 #include "tracker-daemon-glue.h"
 #include "tracker-resources.h"
 #include "tracker-resources-glue.h"
+#include "tracker-resource-class.h"
+#include "tracker-resources-class-glue.h"
 #include "tracker-search.h"
 #include "tracker-search-glue.h"
 #include "tracker-backup.h"
@@ -259,7 +264,9 @@ tracker_dbus_register_objects (TrackerConfig	*config,
 			       TrackerDBIndex	*resources_index,
 			       TrackerProcessor *processor)
 {
-	gpointer object;
+	gpointer object, resources;
+	GSList *event_sources = NULL;
+	TrackerDBResultSet *result_set;
 
 	g_return_val_if_fail (TRACKER_IS_CONFIG (config), FALSE);
 	g_return_val_if_fail (TRACKER_IS_LANGUAGE (language), FALSE);
@@ -290,6 +297,7 @@ tracker_dbus_register_objects (TrackerConfig	*config,
 		g_critical ("Could not create TrackerResources object to register");
 		return FALSE;
 	}
+	resources = object;
 
 	dbus_register_object (connection,
 			      gproxy,
@@ -329,6 +337,72 @@ tracker_dbus_register_objects (TrackerConfig	*config,
 	/* Reverse list since we added objects at the top each time */
 	objects = g_slist_reverse (objects);
 
+	result_set = tracker_data_query_sparql ("SELECT ?class WHERE { ?class tracker:notify true }", NULL);
+
+	if (result_set) {
+		GStrv classes_to_signal;
+		guint ui, count = 0;
+
+		classes_to_signal = tracker_dbus_query_result_to_strv (result_set, 0, &count);
+
+		for (ui = 0; ui < count; ui++) {
+			const gchar *rdf_class = classes_to_signal[ui];
+			gchar *replaced;
+			gchar *path, *uri, *hash;
+
+			uri = g_strdup (rdf_class);
+
+			hash = strrchr (uri, '#');
+			if (hash == NULL) {
+				/* support ontologies whose namespace uri does not end in a hash, e.g. dc */
+				hash = strrchr (uri, '/');
+			}
+			if (hash == NULL) {
+				g_critical ("Unknown namespace of property %s", uri);
+			} else {
+				gchar *namespace_uri = g_strndup (uri, hash - uri + 1);
+				TrackerNamespace *namespace;
+
+				namespace = tracker_ontology_get_namespace_by_uri (namespace_uri);
+				if (namespace == NULL) {
+					g_critical ("Unknown namespace %s of property %s", namespace_uri, uri);
+				} else {
+					replaced = g_strdup_printf ("%s/%s", tracker_namespace_get_prefix (namespace), hash + 1);
+				}
+				g_free (namespace_uri);
+			}
+
+			path = g_strdup_printf (TRACKER_RESOURCES_CLASS_PATH,
+						replaced);
+
+			g_free (replaced);
+
+			/* Add a org.freedesktop.Tracker.Resources.Class */
+			object = tracker_resource_class_new (rdf_class);
+			if (!object) {
+				g_critical ("Could not create TrackerResourcesClass object to register");
+				return FALSE;
+			}
+
+			dbus_register_object (connection,
+					      gproxy,
+					      G_OBJECT (object),
+					      &dbus_glib_tracker_resources_class_object_info,
+					      path);
+			g_free (path);
+
+			/* TrackerResources takes over ownership and unrefs the gobjects too */
+			event_sources = g_slist_prepend (event_sources, g_object_ref (object));
+			objects = g_slist_prepend (objects, object);
+		}
+
+		g_strfreev (classes_to_signal);
+		g_object_unref (result_set);
+	}
+
+
+	tracker_resources_set_event_sources (resources, event_sources);
+
 	return TRUE;
 }
 
@@ -491,6 +565,11 @@ tracker_dbus_indexer_get_proxy (void)
 					 G_TYPE_STRING,
 					 G_TYPE_BOOLEAN,
 					 G_TYPE_INVALID);
+		dbus_g_proxy_add_signal (proxy_for_indexer,
+					 "EventHappened",
+					 TRACKER_TYPE_EVENT_ARRAY,
+					 G_TYPE_INVALID);
+
 	}
 
 	return proxy_for_indexer;
diff --git a/src/trackerd/tracker-resource-class.c b/src/trackerd/tracker-resource-class.c
new file mode 100644
index 0000000..93ca6d3
--- /dev/null
+++ b/src/trackerd/tracker-resource-class.c
@@ -0,0 +1,232 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Authors:
+ *  Philip Van Hoof <philip codeminded be>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <libtracker-common/tracker-dbus.h>
+#include <libtracker-common/tracker-config.h>
+#include <libtracker-common/tracker-ontology.h>
+#include <libtracker-db/tracker-db-dbus.h>
+
+#include "tracker-dbus.h"
+#include "tracker-resource-class.h"
+#include "tracker-marshal.h"
+
+#define TRACKER_RESOURCE_CLASS_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TRACKER_TYPE_RESOURCE_CLASS, TrackerResourceClassPrivate))
+
+typedef struct {
+	gchar *rdf_class;
+	GPtrArray *adds, *ups, *dels;
+} TrackerResourceClassPrivate;
+
+enum {
+	SUBJECTS_ADDED,
+	SUBJECTS_REMOVED,
+	SUBJECTS_CHANGED,
+	LAST_SIGNAL
+};
+
+static void tracker_resource_class_finalize (GObject *object);
+
+G_DEFINE_TYPE(TrackerResourceClass, tracker_resource_class, G_TYPE_OBJECT)
+
+static guint signals[LAST_SIGNAL] = {0};
+
+static void
+tracker_resource_class_class_init (TrackerResourceClassClass *klass)
+{
+	GObjectClass *object_class;
+
+	object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = tracker_resource_class_finalize;
+
+	signals[SUBJECTS_ADDED] =
+		g_signal_new ("subjects-added",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_LAST,
+			      0,
+			      NULL, NULL,
+			      tracker_marshal_VOID__BOXED,
+			      G_TYPE_NONE,
+			      1,
+			      G_TYPE_STRV);
+
+	signals[SUBJECTS_REMOVED] =
+		g_signal_new ("subjects-removed",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_LAST,
+			      0,
+			      NULL, NULL,
+			      tracker_marshal_VOID__BOXED,
+			      G_TYPE_NONE,
+			      1,
+			      G_TYPE_STRV);
+
+	signals[SUBJECTS_CHANGED] =
+		g_signal_new ("subjects-changed",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_LAST,
+			      0,
+			      NULL, NULL,
+			      tracker_marshal_VOID__BOXED,
+			      G_TYPE_NONE,
+			      1,
+			      G_TYPE_STRV);
+
+	g_type_class_add_private (object_class, sizeof (TrackerResourceClassPrivate));
+}
+
+static void
+tracker_resource_class_init (TrackerResourceClass *object)
+{
+}
+
+static void
+tracker_resource_class_finalize (GObject *object)
+{
+	TrackerResourceClassPrivate *priv;
+
+	priv = TRACKER_RESOURCE_CLASS_GET_PRIVATE (object);
+
+	/* Emit pending events */
+	tracker_resource_class_emit_events ((TrackerResourceClass *) object);
+
+	g_free (priv->rdf_class);
+
+	G_OBJECT_CLASS (tracker_resource_class_parent_class)->finalize (object);
+}
+
+TrackerResourceClass *
+tracker_resource_class_new (const gchar *rdf_class)
+{
+	TrackerResourceClass	     *object;
+	TrackerResourceClassPrivate *priv;
+
+	object = g_object_new (TRACKER_TYPE_RESOURCE_CLASS, NULL);
+
+	priv = TRACKER_RESOURCE_CLASS_GET_PRIVATE (object);
+
+	priv->rdf_class = g_strdup (rdf_class);
+
+	return object;
+}
+
+
+const gchar *
+tracker_resource_class_get_rdf_class (TrackerResourceClass  *object)
+{
+	TrackerResourceClassPrivate *priv;
+
+	priv = TRACKER_RESOURCE_CLASS_GET_PRIVATE (object);
+
+	return priv->rdf_class;
+}
+
+void 
+tracker_resource_class_add_event (TrackerResourceClass  *object,
+				  const gchar           *uri,
+				  TrackerDBusEventsType type)
+{
+	TrackerResourceClassPrivate *priv;
+
+	priv = TRACKER_RESOURCE_CLASS_GET_PRIVATE (object);
+
+	switch (type) {
+		case TRACKER_DBUS_EVENTS_TYPE_ADD:
+		if (!priv->adds)
+			priv->adds = g_ptr_array_new ();
+		g_ptr_array_add (priv->adds, g_strdup (uri));
+		break;
+		case TRACKER_DBUS_EVENTS_TYPE_UPDATE:
+		if (!priv->ups)
+			priv->ups = g_ptr_array_new ();
+		g_ptr_array_add (priv->ups, g_strdup (uri));
+		break;
+		case TRACKER_DBUS_EVENTS_TYPE_DELETE:
+		if (!priv->dels)
+			priv->dels = g_ptr_array_new ();
+		g_ptr_array_add (priv->dels, g_strdup (uri));
+		break;
+		default:
+		break;
+	}
+}
+
+static void
+emit_strings (TrackerResourceClass *object, gint signal_, GPtrArray *array)
+{
+	GStrv strings_to_emit;
+	guint i;
+
+	if (array->len > 0) {
+		strings_to_emit = (GStrv) g_malloc0  (sizeof (gchar *) * (array->len + 1));
+
+		for (i = 0; i < array->len; i++) {
+			strings_to_emit[i] = array->pdata [i];
+		}
+
+		g_signal_emit (object, signal_, 0, strings_to_emit);
+
+		/* Normal free, not a GStrv free, we free the strings later */
+		g_free (strings_to_emit);
+	}
+}
+
+static void
+free_array (GPtrArray *array)
+{
+	guint i;
+	for (i = 0; i < array->len; i++) {
+		g_free (array->pdata [i]);
+	}
+	g_ptr_array_free (array, TRUE);
+}
+
+void
+tracker_resource_class_emit_events (TrackerResourceClass  *object)
+{
+	TrackerResourceClassPrivate *priv;
+
+	priv = TRACKER_RESOURCE_CLASS_GET_PRIVATE (object);
+
+	if (priv->adds) {
+		emit_strings (object, signals[SUBJECTS_ADDED], priv->adds);
+		free_array (priv->adds);
+		priv->adds = NULL;
+	}
+
+	if (priv->ups) {
+		emit_strings (object, signals[SUBJECTS_CHANGED], priv->ups);
+		free_array (priv->ups);
+		priv->ups = NULL;
+	}
+
+	if (priv->dels) {
+		emit_strings (object, signals[SUBJECTS_REMOVED], priv->dels);
+		free_array (priv->dels);
+		priv->dels = NULL;
+	}
+}
diff --git a/src/trackerd/tracker-resource-class.h b/src/trackerd/tracker-resource-class.h
new file mode 100644
index 0000000..0c8eb5f
--- /dev/null
+++ b/src/trackerd/tracker-resource-class.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Authors:
+ *  Philip Van Hoof <philip codeminded be>
+ */
+
+#ifndef __TRACKERD_RESOURCES_CLASS_H__
+#define __TRACKERD_RESOURCES_CLASS_H__
+
+#include <glib-object.h>
+#include <libtracker-common/tracker-dbus.h>
+
+#define TRACKER_RESOURCES_CLASS_SERVICE	       "org.freedesktop.Tracker"
+#define TRACKER_RESOURCES_CLASS_PATH	       "/org/freedesktop/Tracker/Resources/Classes/%s"
+#define TRACKER_RESOURCES_CLASS_INTERFACE       "org.freedesktop.Tracker.Resources.Class"
+
+G_BEGIN_DECLS
+
+#define TRACKER_TYPE_RESOURCE_CLASS	       (tracker_resource_class_get_type ())
+#define TRACKER_RESOURCE_CLASS(object)	       (G_TYPE_CHECK_INSTANCE_CAST ((object), TRACKER_TYPE_RESOURCE_CLASS, TrackerResourceClass))
+#define TRACKER_RESOURCE_CLASS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TRACKER_TYPE_RESOURCE_CLASS, TrackerResourceClassClass))
+#define TRACKER_IS_RESOURCE_CLASS(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), TRACKER_TYPE_RESOURCE_CLASS))
+#define TRACKER_IS_RESOURCE_CLASS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TRACKER_TYPE_RESOURCE_CLASS))
+#define TRACKER_RESOURCE_CLASS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), TRACKER_TYPE_RESOURCE_CLASS, TrackerResourceClassClass))
+
+typedef struct TrackerResourceClass	  TrackerResourceClass;
+typedef struct TrackerResourceClassClass TrackerResourceClassClass;
+
+struct TrackerResourceClass {
+	GObject parent;
+};
+
+struct TrackerResourceClassClass {
+	GObjectClass parent;
+};
+
+GType                  tracker_resource_class_get_type      (void);
+TrackerResourceClass  *tracker_resource_class_new           (const gchar *rdf_class);
+
+const gchar *          tracker_resource_class_get_rdf_class (TrackerResourceClass  *object);
+void                   tracker_resource_class_add_event     (TrackerResourceClass  *object,
+							     const gchar           *uri,
+							     TrackerDBusEventsType type);
+void                   tracker_resource_class_emit_events   (TrackerResourceClass  *object);
+
+G_END_DECLS
+
+#endif /* __TRACKERD_RESOURCES_CLASS_H__ */
diff --git a/src/trackerd/tracker-resources.c b/src/trackerd/tracker-resources.c
index a822cd5..9f4676f 100644
--- a/src/trackerd/tracker-resources.c
+++ b/src/trackerd/tracker-resources.c
@@ -38,17 +38,111 @@
 #include "tracker-dbus.h"
 #include "tracker-marshal.h"
 #include "tracker-resources.h"
+#include "tracker-resource-class.h"
 
 G_DEFINE_TYPE(TrackerResources, tracker_resources, G_TYPE_OBJECT)
 
+#define TRACKER_RESOURCES_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TRACKER_TYPE_RESOURCES, TrackerResourcesPrivate))
+
+
+typedef struct {
+	GSList     *event_sources;
+	DBusGProxy *indexer_proxy;
+} TrackerResourcesPrivate;
+
+static void
+free_event_sources (TrackerResourcesPrivate *priv)
+{
+	if (priv->event_sources) {
+		g_slist_foreach (priv->event_sources, 
+				 (GFunc) g_object_unref, NULL);
+		g_slist_free (priv->event_sources);
+
+		priv->event_sources = NULL;
+	}
+}
+
+static void 
+tracker_resources_finalize (GObject	 *object)
+{
+	TrackerResourcesPrivate *priv;
+
+	priv = TRACKER_RESOURCES_GET_PRIVATE (object);
+
+	free_event_sources (priv);
+
+	g_object_unref (priv->indexer_proxy);
+
+	G_OBJECT_CLASS (tracker_resources_parent_class)->finalize (object);
+}
+
 static void
 tracker_resources_class_init (TrackerResourcesClass *klass)
 {
+	GObjectClass *object_class;
+
+	object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = tracker_resources_finalize;
+
+	g_type_class_add_private (object_class, sizeof (TrackerResourcesPrivate));
+}
+
+
+static void
+event_happened_cb (DBusGProxy *proxy,
+		   GPtrArray  *events,
+		   gpointer    user_data)
+{
+	TrackerResources        *object = user_data;
+	TrackerResourcesPrivate *priv;
+	GSList                  *event_sources, *l, *to_emit = NULL;
+	guint                    i;
+
+	priv = TRACKER_RESOURCES_GET_PRIVATE (object);
+
+	event_sources = priv->event_sources;
+
+	for (i = 0; i < events->len; i++) {
+		GValueArray *event = events->pdata[i];
+		const gchar *uri = g_value_get_string (g_value_array_get_nth (event, 0));
+		const gchar *rdf_class = g_value_get_string (g_value_array_get_nth (event, 1));
+		TrackerDBusEventsType type = g_value_get_int (g_value_array_get_nth (event, 2));
+
+		for (l = event_sources; l; l = l->next) {
+			TrackerResourceClass *class_ = l->data;
+			if (g_strcmp0 (rdf_class, tracker_resource_class_get_rdf_class (class_)) == 0) {
+				tracker_resource_class_add_event (class_, uri, type);
+				to_emit = g_slist_prepend (to_emit, class_);
+			}
+		}
+	}
+
+	if (to_emit) {
+		for (l = to_emit; l; l = l->next) {
+			TrackerResourceClass *class_ = l->data;
+			tracker_resource_class_emit_events (class_);
+		}
+
+		g_slist_free (to_emit);
+	}
 }
 
 static void
 tracker_resources_init (TrackerResources *object)
 {
+	TrackerResourcesPrivate *priv;
+	DBusGProxy *proxy = tracker_dbus_indexer_get_proxy ();
+
+	priv = TRACKER_RESOURCES_GET_PRIVATE (object);
+
+	priv->indexer_proxy = g_object_ref (proxy);
+
+	dbus_g_proxy_connect_signal (proxy, "EventHappened",
+				     G_CALLBACK (event_happened_cb),
+				     object,
+				     NULL);
+
 }
 
 TrackerResources *
@@ -261,3 +355,15 @@ tracker_resources_sparql_update (TrackerResources	 *self,
 	tracker_dbus_request_success (request_id);
 }
 
+void 
+tracker_resources_set_event_sources (TrackerResources *object,
+				     GSList           *event_sources)
+{
+	TrackerResourcesPrivate *priv;
+
+	priv = TRACKER_RESOURCES_GET_PRIVATE (object);
+
+	free_event_sources (priv);
+
+	priv->event_sources = event_sources;
+}
diff --git a/src/trackerd/tracker-resources.h b/src/trackerd/tracker-resources.h
index a673b62..cedc4d7 100644
--- a/src/trackerd/tracker-resources.h
+++ b/src/trackerd/tracker-resources.h
@@ -52,6 +52,11 @@ struct TrackerResourcesClass {
 
 GType		 tracker_resources_get_type		 (void);
 TrackerResources *tracker_resources_new			 (void);
+
+void		 tracker_resources_set_event_sources	 (TrackerResources       *object,
+							  GSList                 *event_sources);
+
+/* DBus methods */
 void		 tracker_resources_insert		 (TrackerResources	 *self,
 							  const gchar		 *subject,
 							  const gchar		 *predicate,
@@ -77,6 +82,7 @@ void		 tracker_resources_sparql_update	 (TrackerResources       *object,
 							  DBusGMethodInvocation  *context,
 							  GError		**error);
 
+
 G_END_DECLS
 
 #endif /* __TRACKERD_RESOURCES_H__ */
diff --git a/tests/tracker-indexer/Makefile.am b/tests/tracker-indexer/Makefile.am
index 1462ef6..7b65263 100644
--- a/tests/tracker-indexer/Makefile.am
+++ b/tests/tracker-indexer/Makefile.am
@@ -2,7 +2,8 @@ include $(top_srcdir)/Makefile.decl
 
 noinst_PROGRAMS = $(TEST_PROGS)
 
-TEST_PROGS += tracker-metadata-utils
+TEST_PROGS += tracker-metadata-utils \
+	tracker-events
 
 INCLUDES = 									\
 	-DTEST									\
@@ -25,6 +26,7 @@ INCLUDES = 									\
 
 tracker_metadata_utils_SOURCES = 						\
 	$(top_srcdir)/src/tracker-indexer/tracker-dbus.c			\
+	$(top_srcdir)/src/tracker-indexer/tracker-events.c			\
 	$(top_srcdir)/src/tracker-indexer/tracker-indexer.c			\
 	$(top_srcdir)/src/tracker-indexer/tracker-indexer-module.c		\
 	$(top_srcdir)/src/tracker-indexer/tracker-marshal-main.c		\
@@ -49,3 +51,15 @@ tracker_metadata_utils_LDADD =	                                        	\
 	$(GCOV_LIBS)								\
 	$(RAPTOR_LIBS)								\
 	$(GLIB2_LIBS)							
+
+tracker_events_SOURCES = 							\
+	tracker-events-test.c							\
+	$(top_srcdir)/src/tracker-indexer/tracker-events.c
+
+tracker_events_LDADD = 								\
+	$(top_builddir)/src/libtracker-common/libtracker-common.la 		\
+	$(DBUS_LIBS)								\
+	$(GCOV_LIBS)								\
+	$(GMODULE_LIBS)								\
+	$(GTHREAD_LIBS)								\
+	$(GLIB2_LIBS)							
diff --git a/tests/tracker-indexer/tracker-events-test.c b/tests/tracker-indexer/tracker-events-test.c
new file mode 100644
index 0000000..605318d
--- /dev/null
+++ b/tests/tracker-indexer/tracker-events-test.c
@@ -0,0 +1,187 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Nokia (urho konttori nokia com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+#include <glib.h>
+#include <glib-object.h>
+#include <libtracker-common/tracker-dbus.h>
+#include <tracker-events.h>
+
+
+#define EMAIL_CLASS "http://namespace1/nmo/Email";
+#define FEED_CLASS "http://namespace1/nmo/FeedMessage";
+#define CONTACT_CLASS "http://namespace2/nco/Contact";
+#define NON_SIGNAL_CLASS "http://namespace100/myapp/MyClass";
+
+static GPtrArray *types;
+
+static GStrv
+initialization_callback (void)
+{
+        gchar *klasses[] = {
+                EMAIL_CLASS,
+                FEED_CLASS,
+                CONTACT_CLASS,
+                NULL};
+
+        return g_strdupv (klasses);
+}
+
+static void
+test_events_empty (void)
+{
+        GPtrArray *events = NULL;
+
+        tracker_events_init (initialization_callback);
+
+        events = tracker_events_get_pending ();
+        g_assert (events == NULL);
+
+        tracker_events_reset ();
+
+        tracker_events_shutdown ();
+}
+
+static void
+test_events_reset (void)
+{
+        GPtrArray *events;
+
+        tracker_events_init (initialization_callback);
+
+        tracker_events_insert ("uri://1", EMAIL_CLASS, types,
+                               TRACKER_DBUS_EVENTS_TYPE_ADD);
+
+        events = tracker_events_get_pending ();
+        g_assert_cmpint (events->len, ==, 1);
+
+        /* Try again without reset to ensure the data is
+         * still there 
+         */
+        events = tracker_events_get_pending ();
+        g_assert_cmpint (events->len, ==, 1);
+
+        tracker_events_reset ();
+        tracker_events_shutdown ();
+}
+
+static void
+test_events_insertions (void)
+{
+        GPtrArray *events;
+
+        tracker_events_init (initialization_callback);
+
+        tracker_events_insert ("uri://1", EMAIL_CLASS, types,
+                               TRACKER_DBUS_EVENTS_TYPE_ADD);
+
+        tracker_events_insert ("uri://2", EMAIL_CLASS, types,
+                               TRACKER_DBUS_EVENTS_TYPE_UPDATE);
+
+        tracker_events_insert ("uri://3", EMAIL_CLASS, types,
+                               TRACKER_DBUS_EVENTS_TYPE_DELETE);
+
+        events = tracker_events_get_pending ();
+        g_assert_cmpint (events->len, ==, 2);
+
+        /* Insert class we dont want to signal */
+        tracker_events_insert ("uri://x", NON_SIGNAL_CLASS, types,
+                               TRACKER_DBUS_EVENTS_TYPE_DELETE);
+
+        events = tracker_events_get_pending ();
+        g_assert_cmpint (events->len, ==, 2);
+        
+        tracker_events_reset ();
+        tracker_events_shutdown ();
+}
+
+static void
+test_events_no_allows (void)
+{
+        gint i;
+
+        tracker_events_init (NULL);
+        g_assert (tracker_events_get_pending () == NULL);
+        tracker_events_reset ();
+        g_assert (tracker_events_get_pending () == NULL);
+
+        for (i = 0; i < 10; i++) {
+                tracker_events_insert (g_strdup_printf ("uri://%d", i),
+                                       EMAIL_CLASS, types,
+                                       TRACKER_DBUS_EVENTS_TYPE_ADD);
+        }
+
+        g_assert (tracker_events_get_pending () == NULL);
+        
+        tracker_events_shutdown ();
+}
+
+static void
+test_events_lifecycle (void)
+{
+        /* Shutdown - no init */
+ 	if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) {
+                tracker_events_shutdown ();
+	}
+	g_test_trap_assert_stderr ("*tracker_events already shutdown*");
+
+  	if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) {
+                tracker_events_get_pending ();
+        }
+        g_test_trap_assert_stderr ("*assertion `private != NULL' failed*");
+
+  	if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) {
+                tracker_events_reset ();
+        }
+        g_test_trap_assert_stderr ("*assertion `private != NULL' failed*");
+}
+
+int
+main (int    argc,
+      char **argv)
+{
+	GStrv types_s;
+	guint i;
+
+        g_type_init ();
+        g_thread_init (NULL);
+        g_test_init (&argc, &argv, NULL);
+
+	types = g_ptr_array_new ();
+
+	types_s = initialization_callback ();
+
+	for (i = 0; types_s[i];  i++) {
+		g_ptr_array_add (types, types_s[i]);
+	}
+
+        g_test_add_func ("/tracker/tracker-indexer/tracker-events/empty",
+                         test_events_empty);
+        g_test_add_func ("/tracker/tracker-indexer/tracker-events/reset",
+                         test_events_reset);
+        g_test_add_func ("/tracker/tracker-indexer/tracker-events/insertions",
+                         test_events_insertions);
+        g_test_add_func ("/tracker/tracker-indexer/tracker-events/no-allows",
+                         test_events_no_allows);
+        g_test_add_func ("/tracker/tracker-indexer/tracker-events/lifecycle",
+                         test_events_lifecycle);
+
+	g_ptr_array_free (types, TRUE);
+
+	return g_test_run ();
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]