[tracker/writeback: 23/23] Signalling Writeback in case a property marked as tracker:writeback is changed



commit 4fa1135afb704b84395d946960214d2282d5f8ad
Author: Philip Van Hoof <philip codeminded be>
Date:   Fri Nov 6 13:28:46 2009 +0100

    Signalling Writeback in case a property marked as tracker:writeback is changed

 data/dbus/tracker-resources.xml       |   12 ++
 data/ontologies/90-tracker.ontology   |   16 +++-
 src/tracker-store/Makefile.am         |    2 +
 src/tracker-store/tracker-dbus.c      |    2 +-
 src/tracker-store/tracker-events.c    |    4 +
 src/tracker-store/tracker-main.c      |   23 ++++
 src/tracker-store/tracker-resources.c |  196 ++++++++++++++++++++++++++++++++-
 src/tracker-store/tracker-resources.h |    8 +-
 src/tracker-store/tracker-writeback.c |  158 ++++++++++++++++++++++++++
 src/tracker-store/tracker-writeback.h |   44 ++++++++
 10 files changed, 455 insertions(+), 10 deletions(-)
---
diff --git a/data/dbus/tracker-resources.xml b/data/dbus/tracker-resources.xml
index 7b28ac5..fdefb49 100644
--- a/data/dbus/tracker-resources.xml
+++ b/data/dbus/tracker-resources.xml
@@ -37,5 +37,17 @@
       <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
     </method>
 
+    <!-- Register yourself for Writeback signals -->
+    <method name="RegisterWriteback">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
+      <arg type="s" name="object_path" direction="in" />
+    </method>
+
+<!-- This is a private signal
+   <signal name="Writeback">
+      <arg type="as" name="subjects" />
+   </signal>
+-->
+
   </interface>
 </node>
diff --git a/data/ontologies/90-tracker.ontology b/data/ontologies/90-tracker.ontology
index c15cb5c..709a9a1 100644
--- a/data/ontologies/90-tracker.ontology
+++ b/data/ontologies/90-tracker.ontology
@@ -41,8 +41,20 @@ tracker:mountPoint a rdf:Property ;
 
 tracker:available a rdf:Property ;
 	nrl:maxCardinality 1 ;
-        rdfs:domain nie:DataObject ;
-        rdfs:range xsd:boolean .
+	rdfs:domain nie:DataObject ;
+	rdfs:range xsd:boolean .
+
+tracker:writeback a rdf:Property ;
+	nrl:maxCardinality 1 ;
+	rdfs:domain rdf:Property ;
+	rdfs:range xsd:boolean .
+
+# Remove this afterward
+tracker:writebackTestField a rdf:Property ;
+	nrl:maxCardinality 1 ;
+	tracker:writeback true ;
+	rdfs:domain rdfs:Resource ;
+	rdfs:range xsd:string .
 
 fts: a tracker:Namespace ;
 	tracker:prefix "fts" .
diff --git a/src/tracker-store/Makefile.am b/src/tracker-store/Makefile.am
index b712417..236cae4 100644
--- a/src/tracker-store/Makefile.am
+++ b/src/tracker-store/Makefile.am
@@ -35,6 +35,8 @@ tracker_store_SOURCES =							\
 	tracker-dbus.h							\
 	tracker-events.c						\
 	tracker-events.h						\
+	tracker-writeback.c						\
+	tracker-writeback.h						\
 	tracker-main.c							\
 	tracker-resources.c						\
 	tracker-resources.h						\
diff --git a/src/tracker-store/tracker-dbus.c b/src/tracker-store/tracker-dbus.c
index 9c7b975..a5e1eaf 100644
--- a/src/tracker-store/tracker-dbus.c
+++ b/src/tracker-store/tracker-dbus.c
@@ -214,7 +214,7 @@ tracker_dbus_register_objects (void)
 	objects = g_slist_prepend (objects, object);
 
 	/* Add org.freedesktop.Tracker1.Resources */
-	object = resources = tracker_resources_new ();
+	object = resources = tracker_resources_new (connection);
 	if (!object) {
 		g_critical ("Could not create TrackerResources object to register");
 		return FALSE;
diff --git a/src/tracker-store/tracker-events.c b/src/tracker-store/tracker-events.c
index cf30d0c..5a6de8e 100644
--- a/src/tracker-store/tracker-events.c
+++ b/src/tracker-store/tracker-events.c
@@ -201,6 +201,10 @@ tracker_events_init (TrackerNotifyClassGetter callback)
 	}
 
 	classes_to_signal = (*callback)();
+
+	if (!classes_to_signal)
+		return;
+
 	count = g_strv_length (classes_to_signal);
 	for (i = 0; i < count; i++) {
 		tracker_events_add_allow (classes_to_signal[i]);
diff --git a/src/tracker-store/tracker-main.c b/src/tracker-store/tracker-main.c
index b42dbcb..b12f546 100644
--- a/src/tracker-store/tracker-main.c
+++ b/src/tracker-store/tracker-main.c
@@ -53,6 +53,7 @@
 #include "tracker-dbus.h"
 #include "tracker-config.h"
 #include "tracker-events.h"
+#include "tracker-writeback.h"
 #include "tracker-push.h"
 #include "tracker-backup.h"
 #include "tracker-store.h"
@@ -288,6 +289,25 @@ get_notifiable_classes (void)
 	return classes_to_signal;
 }
 
+
+static GStrv
+get_writeback_predicates (void)
+{
+	TrackerDBResultSet *result_set;
+	GStrv predicates_to_signal = NULL;
+
+	result_set = tracker_data_query_sparql ("SELECT ?predicate WHERE { ?predicate tracker:writeback true }", NULL);
+
+	if (result_set) {
+		guint count = 0;
+
+		predicates_to_signal = tracker_dbus_query_result_to_strv (result_set, 0, &count);
+		g_object_unref (result_set);
+	}
+
+	return predicates_to_signal;
+}
+
 gint
 main (gint argc, gchar *argv[])
 {
@@ -418,6 +438,8 @@ main (gint argc, gchar *argv[])
 	}
 
 	tracker_events_init (get_notifiable_classes);
+	tracker_writeback_init (get_writeback_predicates);
+
 	tracker_push_init ();
 
 	g_message ("Waiting for D-Bus requests...");
@@ -447,6 +469,7 @@ shutdown:
 
 	/* Shutdown major subsystems */
 	tracker_push_shutdown ();
+	tracker_writeback_shutdown ();
 	tracker_events_shutdown ();
 
 	tracker_dbus_shutdown ();
diff --git a/src/tracker-store/tracker-resources.c b/src/tracker-store/tracker-resources.c
index 57833b1..0806a46 100644
--- a/src/tracker-store/tracker-resources.c
+++ b/src/tracker-store/tracker-resources.c
@@ -41,6 +41,7 @@
 #include "tracker-resources.h"
 #include "tracker-resource-class.h"
 #include "tracker-events.h"
+#include "tracker-writeback.h"
 #include "tracker-store.h"
 
 #define RDF_PREFIX TRACKER_RDF_PREFIX
@@ -51,9 +52,15 @@ 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))
 
+enum {
+	PROP_0,
+	PROP_CONNECTION
+};
 
 typedef struct {
-	GSList     *event_sources;
+	GSList *event_sources;
+	GPtrArray *writeback_destinations;
+	DBusGConnection *connection;
 } TrackerResourcesPrivate;
 
 typedef struct {
@@ -80,11 +87,55 @@ tracker_resources_finalize (GObject	 *object)
 
 	priv = TRACKER_RESOURCES_GET_PRIVATE (object);
 
+	dbus_g_connection_unref (priv->connection);
+
 	free_event_sources (priv);
 
 	G_OBJECT_CLASS (tracker_resources_parent_class)->finalize (object);
 }
 
+
+static void
+tracker_resources_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+	TrackerResourcesPrivate *priv;
+
+	priv = TRACKER_RESOURCES_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_CONNECTION:
+		priv->connection = dbus_g_connection_ref (g_value_get_pointer (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+tracker_resources_get_property (GObject    *object,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+	TrackerResourcesPrivate *priv;
+
+	priv = TRACKER_RESOURCES_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_CONNECTION:
+		g_value_set_pointer (value, priv->connection);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+
 static void
 tracker_resources_class_init (TrackerResourcesClass *klass)
 {
@@ -93,6 +144,15 @@ tracker_resources_class_init (TrackerResourcesClass *klass)
 	object_class = G_OBJECT_CLASS (klass);
 
 	object_class->finalize = tracker_resources_finalize;
+	object_class->get_property = tracker_resources_get_property;
+	object_class->set_property = tracker_resources_set_property;
+
+	g_object_class_install_property (object_class,
+	                                 PROP_CONNECTION,
+	                                 g_param_spec_pointer ("connection",
+	                                                       "connection",
+	                                                       "connection",
+	                                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_type_class_add_private (object_class, sizeof (TrackerResourcesPrivate));
 }
@@ -101,12 +161,19 @@ tracker_resources_class_init (TrackerResourcesClass *klass)
 static void
 tracker_resources_init (TrackerResources *object)
 {
+	TrackerResourcesPrivate *priv;
+
+	priv = TRACKER_RESOURCES_GET_PRIVATE (object);
+
+	priv->writeback_destinations = g_ptr_array_new ();
 }
 
 TrackerResources *
-tracker_resources_new (void)
+tracker_resources_new (DBusGConnection *connection)
 {
-	return g_object_new (TRACKER_TYPE_RESOURCES, NULL);
+	return g_object_new (TRACKER_TYPE_RESOURCES, 
+	                     "connection", connection,
+	                     NULL);
 }
 
 /*
@@ -344,6 +411,56 @@ tracker_resources_batch_commit (TrackerResources	 *self,
 
 
 static void
+tracker_resources_register_writeback_proxy_destroyed (DBusGProxy       *proxy,
+                                                      TrackerResources *object)
+{
+	TrackerResourcesPrivate *priv;
+
+	priv = TRACKER_RESOURCES_GET_PRIVATE (object);
+
+	while (g_ptr_array_remove (priv->writeback_destinations, proxy)) {
+		/* Should we unref proxy here too? I think not. I think dbus-
+		 * glib garbage collects it in a mainloop iteration. Right? */
+	}
+}
+
+void 
+tracker_resources_register_writeback  (TrackerResources       *object,
+                                       const gchar            *object_path,
+                                       DBusGMethodInvocation  *context,
+                                       GError                **error)
+{
+	TrackerResourcesPrivate *priv;
+	guint request_id;
+	gchar *sender;
+	DBusGProxy *proxy;
+
+	priv = TRACKER_RESOURCES_GET_PRIVATE (object);
+
+	request_id = tracker_dbus_get_next_request_id ();
+
+	sender = dbus_g_method_get_sender (context);
+
+	tracker_dbus_request_new (request_id,
+	                          "D-Bus request for writeback registration: '%s'",
+	                          sender);
+
+	proxy = dbus_g_proxy_new_for_name (priv->connection,
+	                                   sender,
+	                                   object_path,
+	                                   "org.freedesktop.Tracker1.WritebackRecipient");
+
+	g_ptr_array_add (priv->writeback_destinations, proxy);
+
+	g_signal_connect (proxy, "destroy",
+	                  G_CALLBACK (tracker_resources_register_writeback_proxy_destroyed),
+	                  object);
+
+	dbus_g_method_return (context);
+	tracker_dbus_request_success (request_id);
+}
+
+static void
 on_statements_committed (gpointer user_data)
 {
 	GPtrArray *events;
@@ -355,6 +472,7 @@ on_statements_committed (gpointer user_data)
 	 * of tracker-store.c */
 	tracker_store_flush_journal ();
 
+	/* Class signals feature */
 	events = tracker_events_get_pending ();
 
 	if (events) {
@@ -362,7 +480,7 @@ on_statements_committed (gpointer user_data)
 		guint i;
 		GHashTable *to_emit = NULL;
 
-		event_sources =priv->event_sources;
+		event_sources = priv->event_sources;
 
 		for (i = 0; i < events->len; i++) {
 			GValueArray *event = events->pdata[i];
@@ -399,6 +517,67 @@ on_statements_committed (gpointer user_data)
 	}
 
 	tracker_events_reset ();
+
+	/* Writeback feature */
+	events = tracker_writeback_get_pending ();
+
+	if (events) {
+		guint t;
+		DBusConnection *connection;
+
+		connection = dbus_g_connection_get_connection (priv->connection);
+
+		for (t = 0; t < priv->writeback_destinations->len; t++) {
+			const gchar    *destination;
+			DBusMessageIter iter;
+			DBusMessageIter strv_iter;
+			DBusMessage    *message;
+			guint           n;
+			DBusGProxy     *sender;
+
+			/* Get the destination, we do this to reduce broadcasted
+			 * signal's DBus traffic. By setting destination we 
+			 * ensure that only the explicitly registered ones awake.
+			 * This might be unnecessary, perhaps we can just do a
+			 * broadcast signal instead too? */
+
+			sender = g_ptr_array_index (priv->writeback_destinations, t);
+			destination = dbus_g_proxy_get_bus_name (sender);
+
+			message = dbus_message_new_signal (TRACKER_RESOURCES_PATH, 
+			                                   TRACKER_RESOURCES_INTERFACE, 
+			                                   "Writeback");
+
+			/* The dbus-glib library can't do this yet, this is why
+			 * you are seeing raw DBus API usage. No panic. */
+
+			dbus_message_set_destination (message, destination);
+
+			dbus_message_iter_init_append (message, &iter);
+
+			dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, 
+			                                  DBUS_TYPE_STRING_AS_STRING, 
+			                                  &strv_iter);
+
+			for (n = 0; n < events->len; n++) {
+				const gchar *writeback_subject;
+
+				writeback_subject = g_ptr_array_index (events, n);
+
+				dbus_message_iter_append_basic (&strv_iter, 
+				                                DBUS_TYPE_STRING, 
+				                                &writeback_subject);
+			}
+
+			dbus_message_iter_close_container (&iter, &strv_iter);
+
+			dbus_connection_send (connection, message, NULL);
+
+			dbus_message_unref (message);
+		}
+	}
+
+	tracker_writeback_reset ();
 }
 
 
@@ -406,6 +585,7 @@ static void
 on_statements_rolled_back (gpointer user_data)
 {
 	tracker_events_reset ();
+	tracker_writeback_reset ();
 }
 
 static void
@@ -421,6 +601,9 @@ on_statement_inserted (const gchar *graph,
 	} else {
 		tracker_events_insert (subject, predicate, object, rdf_types, TRACKER_DBUS_EVENTS_TYPE_UPDATE);
 	}
+
+	/* For predicates it's always update here */
+	tracker_writeback_check (graph, subject, predicate, object);
 }
 
 static void
@@ -436,8 +619,10 @@ on_statement_deleted (const gchar *graph,
 	} else {
 		tracker_events_insert (subject, predicate, object, rdf_types, TRACKER_DBUS_EVENTS_TYPE_UPDATE);
 	}
-}
 
+	/* For predicates it's always delete here */
+	tracker_writeback_check (graph, subject, predicate, object);
+}
 
 void 
 tracker_resources_prepare (TrackerResources *object,
@@ -463,3 +648,4 @@ tracker_resources_unreg_batches (TrackerResources *object,
 {
 	tracker_store_unreg_batches (old_owner);
 }
+
diff --git a/src/tracker-store/tracker-resources.h b/src/tracker-store/tracker-resources.h
index aa135d7..a640c3d 100644
--- a/src/tracker-store/tracker-resources.h
+++ b/src/tracker-store/tracker-resources.h
@@ -49,7 +49,7 @@ struct TrackerResourcesClass {
 };
 
 GType             tracker_resources_get_type            (void);
-TrackerResources *tracker_resources_new                 (void);
+TrackerResources *tracker_resources_new                 (DBusGConnection        *connection);
 void              tracker_resources_prepare             (TrackerResources       *object,
 							 GSList                 *event_sources);
 void              tracker_resources_unreg_batches       (TrackerResources       *object,
@@ -75,7 +75,11 @@ void              tracker_resources_batch_sparql_update (TrackerResources
 void              tracker_resources_batch_commit        (TrackerResources       *object,
 							 DBusGMethodInvocation  *context,
 							 GError                **error);
- 
+void              tracker_resources_register_writeback  (TrackerResources       *object,
+							 const gchar            *object_path,
+							 DBusGMethodInvocation  *context,
+							 GError                **error);
+
 G_END_DECLS
 
 #endif /* __TRACKER_STORE_RESOURCES_H__ */
diff --git a/src/tracker-store/tracker-writeback.c b/src/tracker-store/tracker-writeback.c
new file mode 100644
index 0000000..dcbae14
--- /dev/null
+++ b/src/tracker-store/tracker-writeback.c
@@ -0,0 +1,158 @@
+/* -*- 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-writeback.h"
+
+typedef struct {
+	GHashTable *allowances;
+	GPtrArray *events;
+} WritebackPrivate;
+
+static GStaticPrivate private_key = G_STATIC_PRIVATE_INIT;
+
+static void 
+tracker_writeback_add_allow (const gchar *predicate)
+{
+	WritebackPrivate *private;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	g_hash_table_insert (private->allowances, g_strdup (predicate),
+	                     GINT_TO_POINTER (TRUE));
+}
+
+static gboolean
+is_allowed (WritebackPrivate *private, const gchar *rdf_predicate)
+{
+	return (g_hash_table_lookup (private->allowances, rdf_predicate) != NULL) ? TRUE : FALSE;
+}
+
+void 
+tracker_writeback_check (const gchar *graph,
+                         const gchar *subject, 
+                         const gchar *predicate,
+                         const gchar *object)
+{
+	WritebackPrivate *private;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	if (is_allowed (private, predicate)) {
+		if (!private->events)
+			private->events = g_ptr_array_new ();
+		g_ptr_array_add (private->events, g_strdup (subject));
+	}
+}
+
+void 
+tracker_writeback_reset (void)
+{
+	WritebackPrivate *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_free (private->events->pdata[i]);
+		}
+		g_ptr_array_free (private->events, TRUE);
+
+		private->events = NULL;
+	}
+}
+
+GPtrArray *
+tracker_writeback_get_pending (void)
+{
+	WritebackPrivate *private;
+
+	private = g_static_private_get (&private_key);
+	g_return_val_if_fail (private != NULL, NULL);
+
+	return private->events;
+}
+
+static void
+free_private (WritebackPrivate *private)
+{
+	g_hash_table_unref (private->allowances);
+	g_free (private);
+}
+
+void 
+tracker_writeback_init (TrackerWritebackPredicateGetter callback)
+{
+	WritebackPrivate *private;
+	GStrv          predicates_to_signal;
+	gint           i, count;
+
+	private = g_new0 (WritebackPrivate, 1);
+
+	g_static_private_set (&private_key,
+			      private,
+			      (GDestroyNotify) free_private);
+
+	private->allowances = g_hash_table_new_full (g_str_hash, g_str_equal,
+	                                             (GDestroyNotify) g_free,
+	                                             (GDestroyNotify) NULL);
+
+	private->events = NULL;
+
+	if (!callback) {
+		return;
+	}
+
+	predicates_to_signal = (*callback)();
+
+	if (!predicates_to_signal)
+		return;
+
+	count = g_strv_length (predicates_to_signal);
+	for (i = 0; i < count; i++) {
+		tracker_writeback_add_allow (predicates_to_signal[i]);
+	}
+
+	g_strfreev (predicates_to_signal);
+}
+
+void 
+tracker_writeback_shutdown (void)
+{
+	WritebackPrivate *private;
+
+	private = g_static_private_get (&private_key);
+	if (private != NULL) {
+		tracker_writeback_reset ();
+		g_static_private_set (&private_key, NULL, NULL);
+	} else {
+		g_warning ("tracker_writeback already shutdown");
+	}
+}
diff --git a/src/tracker-store/tracker-writeback.h b/src/tracker-store/tracker-writeback.h
new file mode 100644
index 0000000..4934f06
--- /dev/null
+++ b/src/tracker-store/tracker-writeback.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009, 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_WRITEBACK_H__
+#define __TRACKER_WRITEBACK_H__
+
+#include <libtracker-common/tracker-dbus.h>
+
+G_BEGIN_DECLS
+
+typedef GStrv (*TrackerWritebackPredicateGetter) (void);
+
+void       tracker_writeback_init        (TrackerWritebackPredicateGetter  callback);
+void       tracker_writeback_shutdown    (void);
+void       tracker_writeback_check       (const gchar              *graph,
+                                          const gchar              *subject,
+                                          const gchar              *predicate,
+                                          const gchar              *object);
+GPtrArray *tracker_writeback_get_pending (void);
+void       tracker_writeback_reset       (void);
+
+G_END_DECLS
+
+#endif /* __TRACKER_WRITEBACK_H__ */



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