tracker: Use static client D-Bus syntax
authorZeeshan Ali (Khattak) <zeeshanak@gnome.org>
Wed, 14 Oct 2009 17:33:12 +0000 (20:33 +0300)
committerZeeshan Ali (Khattak) <zeeshanak@gnome.org>
Fri, 16 Oct 2009 16:19:13 +0000 (19:19 +0300)
This also implies that we now use multidimensional arrays to deal with
search results. This combination of static D-Bus and multidimensional
arrays gives us quite a speed boost.

src/plugins/tracker/Makefile.am
src/plugins/tracker/rygel-tracker-get-metadata-result.vala [deleted file]
src/plugins/tracker/rygel-tracker-interfaces.vala [new file with mode: 0644]
src/plugins/tracker/rygel-tracker-keywords.vala
src/plugins/tracker/rygel-tracker-metadata-values.vala
src/plugins/tracker/rygel-tracker-plugin-factory.vala
src/plugins/tracker/rygel-tracker-search-container.vala
src/plugins/tracker/rygel-tracker-search-result.vala [deleted file]

index 7cee5c0..2418883 100644 (file)
@@ -15,14 +15,13 @@ librygel_media_tracker_la_SOURCES = \
                                    rygel-tracker-metadata-values.vala \
                                    rygel-tracker-keywords.vala \
                                    rygel-tracker-search-container.vala \
-                                   rygel-tracker-search-result.vala \
-                                   rygel-tracker-get-metadata-result.vala \
                                    rygel-tracker-item.vala \
                                    rygel-tracker-video-item.vala \
                                    rygel-tracker-music-item.vala \
                                    rygel-tracker-image-item.vala \
                                    rygel-tracker-plugin.vala \
-                                   rygel-tracker-plugin-factory.vala
+                                   rygel-tracker-plugin-factory.vala \
+                                   rygel-tracker-interfaces.vala
 
 librygel_media_tracker_la_VALAFLAGS = \
        --vapidir=$(top_srcdir)/src/rygel \
diff --git a/src/plugins/tracker/rygel-tracker-get-metadata-result.vala b/src/plugins/tracker/rygel-tracker-get-metadata-result.vala
deleted file mode 100644 (file)
index ab059df..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2009 Nokia Corporation.
- *
- * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
- *
- * This file is part of Rygel.
- *
- * Rygel is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Rygel 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/**
- * Handles Tracker Metadata.Get method results.
- *
- */
-public class Rygel.TrackerGetMetadataResult :
-             Rygel.SimpleAsyncResult<MediaObject> {
-    protected string item_id;
-    protected string item_path;
-    protected string item_service;
-
-    public TrackerGetMetadataResult (TrackerSearchContainer search_container,
-                                     AsyncReadyCallback     callback,
-                                     string                 item_id) {
-        base (search_container, callback);
-        this.item_id = item_id;
-    }
-
-    public void ready (string[] metadata, Error error) {
-        if (error != null) {
-            this.error = error;
-
-            this.complete ();
-            return;
-        }
-
-        var search_container = (TrackerSearchContainer) this.source_object;
-
-        this.data = search_container.create_item (this.item_service,
-                                                  this.item_path,
-                                                  metadata);
-
-        this.complete ();
-    }
-}
diff --git a/src/plugins/tracker/rygel-tracker-interfaces.vala b/src/plugins/tracker/rygel-tracker-interfaces.vala
new file mode 100644 (file)
index 0000000..a4b9def
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
+ *                               <zeeshan.ali@nokia.com>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using DBus;
+
+[DBus (name = "org.freedesktop.Tracker")]
+public interface Rygel.TrackerIface : DBus.Object {
+    public abstract int get_version () throws DBus.Error;
+}
+
+[DBus (name = "org.freedesktop.Tracker.Keywords")]
+public interface Rygel.TrackerKeywordsIface : DBus.Object {
+    public abstract string[,] get_list (string service) throws DBus.Error;
+}
+
+[DBus (name = "org.freedesktop.Tracker.Metadata")]
+public interface Rygel.TrackerMetadataIface: DBus.Object {
+    public abstract string[,] get_unique_values (string   service,
+                                                 string[] meta_types,
+                                                 string   query,
+                                                 bool     descending,
+                                                 int      offset,
+                                                 int      max_hits)
+                                                 throws DBus.Error;
+
+    public abstract string[] @get (string   service_type,
+                                   string   uri,
+                                   string[] keys)
+                                   throws DBus.Error;
+}
+
+[DBus (name = "org.freedesktop.Tracker.Search")]
+public interface Rygel.TrackerSearchIface: DBus.Object {
+    public abstract string[,] query (int live_query_id,
+                                     string   service,
+                                     string[] fields,
+                                     string   search_text,
+                                     string[] keywords,
+                                     string   query_condition,
+                                     bool     sort_by_service,
+                                     string[] sort_fields,
+                                     bool     sort_descending,
+                                     int      offset,
+                                     int      max_hits)
+                                     throws DBus.Error;
+}
index cd7b8ff..2197b71 100644 (file)
@@ -32,12 +32,11 @@ public class Rygel.TrackerKeywords : Rygel.SimpleContainer {
     /* class-wide constants */
     private const string TRACKER_SERVICE = "org.freedesktop.Tracker";
     private const string KEYWORDS_PATH = "/org/freedesktop/Tracker/Keywords";
-    private const string KEYWORDS_IFACE = "org.freedesktop.Tracker.Keywords";
 
     private const string SERVICE = "Files";
     private const string TITLE = "Tags";
 
-    public dynamic DBus.Object keywords;
+    public TrackerKeywordsIface keywords;
 
     public TrackerKeywords (string         id,
                             MediaContainer parent) {
@@ -45,28 +44,29 @@ public class Rygel.TrackerKeywords : Rygel.SimpleContainer {
 
         try {
             this.create_proxies ();
-
-            /* FIXME: We need to hook to some tracker signals to keep
-             *        this field up2date at all times
-             */
-            this.keywords.GetList (SERVICE, on_get_keywords_cb);
-        } catch (GLib.Error error) {
+        } catch (DBus.Error error) {
             critical ("Failed to create to Session bus: %s\n",
                       error.message);
+
+            return;
         }
-    }
 
-    private void on_get_keywords_cb (string[][] keywords_list,
-                                     GLib.Error error) {
-        if (error != null) {
+        string[,] keywords_list;
+
+        try {
+            /* FIXME: We need to hook to some tracker signals to keep
+             *        this field up2date at all times
+             */
+            keywords_list = this.keywords.get_list (SERVICE);
+        } catch (DBus.Error error) {
             critical ("error getting all keywords: %s", error.message);
 
             return;
         }
 
         /* Iterate through all the values */
-        for (uint i = 0; i < keywords_list.length; i++) {
-            string keyword = keywords_list[i][0];
+        for (uint i = 0; i < keywords_list.length[0]; i++) {
+            string keyword = keywords_list[i0];
 
             var keywords = new string[] { keyword };
 
@@ -87,8 +87,8 @@ public class Rygel.TrackerKeywords : Rygel.SimpleContainer {
         DBus.Connection connection = DBus.Bus.get (DBus.BusType.SESSION);
 
         this.keywords = connection.get_object (TRACKER_SERVICE,
-                                               KEYWORDS_PATH,
-                                               KEYWORDS_IFACE);
+                                               KEYWORDS_PATH)
+                                               as TrackerKeywordsIface;
     }
 }
 
index b7f3c09..d39f27d 100644 (file)
@@ -32,7 +32,6 @@ public class Rygel.TrackerMetadataValues : Rygel.SimpleContainer {
     /* class-wide constants */
     private const string TRACKER_SERVICE = "org.freedesktop.Tracker";
     private const string METADATA_PATH = "/org/freedesktop/Tracker/Metadata";
-    private const string METADATA_IFACE = "org.freedesktop.Tracker.Metadata";
 
     private const string SERVICE = "Files";
     private const string QUERY_CONDITION =
@@ -43,7 +42,7 @@ public class Rygel.TrackerMetadataValues : Rygel.SimpleContainer {
                 "</rdfq:equals>\n" +
         "</rdfq:Condition>";
 
-    public dynamic DBus.Object metadata;
+    public TrackerMetadataIface metadata;
 
     public string key;
 
@@ -57,28 +56,28 @@ public class Rygel.TrackerMetadataValues : Rygel.SimpleContainer {
 
         try {
             this.create_proxies ();
+        } catch (DBus.Error error) {
+            critical ("Failed to create to Session bus: %s\n",
+                      error.message);
+
+            return;
+        }
+
+        string[,] values;
 
+        try {
             var keys = new string[] { this.key };
 
             /* FIXME: We need to hook to some tracker signals to keep
              *        this field up2date at all times
              */
-            this.metadata.GetUniqueValues (SERVICE,
-                                           keys,
-                                           "",
-                                           false,
-                                           0,
-                                           -1,
-                                           on_get_unique_values_cb);
-        } catch (GLib.Error error) {
-            critical ("Failed to create to Session bus: %s\n",
-                      error.message);
-        }
-    }
-
-    private void on_get_unique_values_cb (string[][] search_result,
-                                          GLib.Error error) {
-        if (error != null) {
+            values = this.metadata.get_unique_values (SERVICE,
+                                                    keys,
+                                                    "",
+                                                    false,
+                                                    0,
+                                                    -1);
+        } catch (DBus.Error error) {
             critical ("error getting all values for '%s': %s",
                       this.key,
                       error.message);
@@ -87,8 +86,8 @@ public class Rygel.TrackerMetadataValues : Rygel.SimpleContainer {
         }
 
         /* Iterate through all the values */
-        for (uint i = 0; i < search_result.length; i++) {
-            string value = search_result[i][0];
+        for (uint i = 0; i < values.length[0]; i++) {
+            string value = values[i, 0];
 
             if (value == "") {
                 continue;
@@ -113,8 +112,8 @@ public class Rygel.TrackerMetadataValues : Rygel.SimpleContainer {
         DBus.Connection connection = DBus.Bus.get (DBus.BusType.SESSION);
 
         this.metadata = connection.get_object (TRACKER_SERVICE,
-                                               METADATA_PATH,
-                                               METADATA_IFACE);
+                                               METADATA_PATH)
+                                               as TrackerMetadataIface;
     }
 }
 
index 09c5f48..f057752 100644 (file)
@@ -32,39 +32,29 @@ private TrackerPluginFactory plugin_factory;
 public void module_init (PluginLoader loader) {
     try {
         plugin_factory = new TrackerPluginFactory (loader);
-    } catch (DBus.Error error) {
-        critical ("Failed to fetch list of external services: %s\n",
-                error.message);
+    } catch (DBus.Error err) {
+        warning ("Failed to start Tracker service: " +
+                 err.message +
+                 ". Tracker plugin disabled.");
     }
 }
 
 public class TrackerPluginFactory {
     private const string TRACKER_SERVICE = "org.freedesktop.Tracker";
     private const string TRACKER_OBJECT = "/org/freedesktop/Tracker";
-    private const string TRACKER_IFACE = "org.freedesktop.Tracker";
 
-    dynamic DBus.Object tracker;
-    PluginLoader        loader;
+    TrackerIface tracker;
+    PluginLoader loader;
 
     public TrackerPluginFactory (PluginLoader loader) throws DBus.Error {
         var connection = DBus.Bus.get (DBus.BusType.SESSION);
 
         this.tracker = connection.get_object (TRACKER_SERVICE,
-                                              TRACKER_OBJECT,
-                                              TRACKER_IFACE);
+                                              TRACKER_OBJECT)
+                                              as TrackerIface;
         this.loader = loader;
 
-        tracker.GetVersion (this.get_version_cb);
-    }
-
-    private void get_version_cb (int32 version, GLib.Error err) {
-        if (err != null) {
-            warning ("Failed to start Tracker service: %s\n",
-                     err.message);
-            warning ("Tracker plugin disabled.\n");
-
-            return;
-        }
+        this.tracker.get_version ();
 
         this.loader.add_plugin (new TrackerPlugin ());
     }
index f56bb50..5e2159f 100644 (file)
@@ -38,9 +38,8 @@ public class Rygel.TrackerSearchContainer : Rygel.MediaContainer {
     private const string METADATA_PATH = "/org/freedesktop/Tracker/Metadata";
     private const string METADATA_IFACE = "org.freedesktop.Tracker.Metadata";
 
-    public dynamic DBus.Object metadata;
-    public dynamic DBus.Object search;
-    public dynamic DBus.Object tracker;
+    public TrackerMetadataIface metadata;
+    public TrackerSearchIface search;
 
     public string service;
 
@@ -81,18 +80,20 @@ public class Rygel.TrackerSearchContainer : Rygel.MediaContainer {
             // We are performing actual search (though an optimized one) to get
             // the hitcount rather than GetHitCount because GetHitCount only
             // allows us to get hit count for Text searches.
-            this.search.Query (0,
-                               this.service,
-                               new string[0],
-                               "",
-                               this.keywords,
-                               this.query_condition,
-                               false,
-                               new string[0],
-                               false,
-                               0,
-                               -1,
-                               on_search_query_cb);
+            var search_result = this.search.query (0,
+                                                   this.service,
+                                                   new string[0],
+                                                   "",
+                                                   this.keywords,
+                                                   this.query_condition,
+                                                   false,
+                                                   new string[0],
+                                                   false,
+                                                   0,
+                                                   -1);
+
+            this.child_count = search_result.length[0];
+            this.updated ();
         } catch (GLib.Error error) {
             critical ("error getting items under service '%s': %s",
                       this.service,
@@ -102,52 +103,50 @@ public class Rygel.TrackerSearchContainer : Rygel.MediaContainer {
         }
     }
 
-    private void on_search_query_cb (string[][] search_result,
-                                     GLib.Error error) {
-        if (error != null) {
-            critical ("error getting items under service '%s': %s",
-                      this.service,
-                      error.message);
-
-            return;
-        }
-
-        this.child_count = search_result.length;
-        this.updated ();
-    }
-
     public override void get_children (uint               offset,
                                        uint               max_count,
                                        Cancellable?       cancellable,
                                        AsyncReadyCallback callback) {
-        var res = new TrackerSearchResult (this, callback);
-
+        var res = new SimpleAsyncResult<ArrayList<MediaObject>> (this,
+                                                                 callback);
+        res.data = new ArrayList<MediaObject> ();
         this.results.add (res);
 
         try {
-            this.search.Query (0,
-                               this.service,
-                               TrackerItem.get_metadata_keys (),
-                               "",
-                               this.keywords,
-                               this.query_condition,
-                               false,
-                               new string[0],
-                               false,
-                               (int) offset,
-                               (int) max_count,
-                               res.ready);
+            string[] keys = TrackerItem.get_metadata_keys ();
+
+            var search_result = this.search.query (0,
+                                                   this.service,
+                                                   keys,
+                                                   "",
+                                                   this.keywords,
+                                                   this.query_condition,
+                                                   false,
+                                                   new string[0],
+                                                   false,
+                                                   (int) offset,
+                                                   (int) max_count);
+
+            /* Iterate through all items */
+            for (uint i = 0; i < search_result.length[0]; i++) {
+                string path = search_result[i, 0];
+                string service = search_result[i, 1];
+                string[] metadata = this.slice_strvv_tail (search_result, i, 2);
+
+                var item = this.create_item (service, path, metadata);
+                res.data.add (item);
+            }
         } catch (GLib.Error error) {
             res.error = error;
-
-            res.complete_in_idle ();
         }
+
+        res.complete_in_idle ();
     }
 
     public override Gee.List<MediaObject>? get_children_finish (
                                                          AsyncResult res)
                                                          throws GLib.Error {
-        var search_res = (Rygel.TrackerSearchResult) res;
+        var search_res = res as SimpleAsyncResult<ArrayList<MediaObject>>;
 
         this.results.remove (search_res);
 
@@ -161,17 +160,16 @@ public class Rygel.TrackerSearchContainer : Rygel.MediaContainer {
     public override void find_object (string             id,
                                       Cancellable?       cancellable,
                                       AsyncReadyCallback callback) {
-        var res = new TrackerGetMetadataResult (this, callback, id);
+        var res = new SimpleAsyncResult<MediaObject> (this, callback);
 
         this.results.add (res);
 
         try {
             string parent_id;
+            string service;
 
-            res.item_path = this.get_item_info (id,
-                                                out parent_id,
-                                                out res.item_service);
-            if (res.item_path == null) {
+            var path = this.get_item_info (id, out parent_id, out service);
+            if (path == null) {
                 res.complete_in_idle ();
 
                 return;
@@ -179,20 +177,21 @@ public class Rygel.TrackerSearchContainer : Rygel.MediaContainer {
 
             string[] keys = TrackerItem.get_metadata_keys ();
 
-            this.metadata.Get (res.item_service,
-                               res.item_path,
-                               keys,
-                               res.ready);
-        } catch (GLib.Error error) {
-            res.error = error;
+            var values = this.metadata.get (service, path, keys);
 
-            res.complete_in_idle ();
+            res.data = this.create_item (service, path, values);
+        } catch (DBus.Error error) {
+            res.error = error;
         }
+
+        res.complete_in_idle ();
     }
 
     public override MediaObject? find_object_finish (AsyncResult res)
                                                      throws GLib.Error {
-        var metadata_res = (TrackerGetMetadataResult) res;
+        var metadata_res = res as SimpleAsyncResult<MediaObject>;
+
+        this.results.remove (metadata_res);
 
         if (metadata_res.error != null) {
             throw metadata_res.error;
@@ -258,14 +257,30 @@ public class Rygel.TrackerSearchContainer : Rygel.MediaContainer {
         DBus.Connection connection = DBus.Bus.get (DBus.BusType.SESSION);
 
         this.metadata = connection.get_object (TRACKER_SERVICE,
-                                               METADATA_PATH,
-                                               METADATA_IFACE);
+                                               METADATA_PATH)
+                                               as TrackerMetadataIface;
         this.search = connection.get_object (TRACKER_SERVICE,
-                                             SEARCH_PATH,
-                                             SEARCH_IFACE);
-        this.tracker = connection.get_object (TRACKER_SERVICE,
-                                              TRACKER_PATH,
-                                              TRACKER_IFACE);
+                                             SEARCH_PATH)
+                                             as TrackerSearchIface;
+    }
+
+    /**
+     * Chops the tail of a particular row in a 2-dimensional string array.
+     *
+     * param strvv the 2-dimenstional string array to chop the tail of.
+     * param row the row whose tail needs to be chopped off.
+     * param index index of the first element in the tail.
+     *
+     * FIXME: Stop using it once vala supports array[N:M] syntax.
+     */
+    private string[] slice_strvv_tail (string[,] strvv, uint row, uint index) {
+        var slice = new string[strvv.length[1] - index];
+
+        for (var i = 0; i < slice.length; i++) {
+            slice[i] = strvv[row, i + index];
+        }
+
+        return slice;
     }
 }
 
diff --git a/src/plugins/tracker/rygel-tracker-search-result.vala b/src/plugins/tracker/rygel-tracker-search-result.vala
deleted file mode 100644 (file)
index 7af3c80..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2009 Nokia Corporation.
- *
- * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
- *
- * This file is part of Rygel.
- *
- * Rygel is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Rygel 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-using Gee;
-
-/**
- * Handles Tracker Search.Query method results.
- *
- */
-public class Rygel.TrackerSearchResult :
-             Rygel.SimpleAsyncResult<Gee.List<MediaObject>> {
-    public TrackerSearchResult (TrackerSearchContainer search_container,
-                                AsyncReadyCallback     callback) {
-        base (search_container, callback);
-
-        this.data = new ArrayList<MediaObject> ();
-    }
-
-    public void ready (string[][] search_result, GLib.Error error) {
-        if (error != null) {
-            this.error = error;
-
-            this.complete ();
-            return;
-        }
-
-        var search_container = (TrackerSearchContainer) this.source_object;
-
-        /* Iterate through all items */
-        for (uint i = 0; i < search_result.length; i++) {
-            string child_path = search_result[i][0];
-            string service = search_result[i][1];
-            string[] metadata = this.slice_strv_tail (search_result[i], 2);
-
-            var item = search_container.create_item (service,
-                                                     child_path,
-                                                     metadata);
-            this.data.add (item);
-        }
-
-        this.complete ();
-    }
-
-    /**
-     * Chops the tail of a string array.
-     *
-     * param strv the string to chop the tail of.
-     * param index index of the first element in the tail.
-     *
-     * FIXME: Stop using it once vala supports array[N:M] syntax.
-     */
-    private string[] slice_strv_tail (string[] strv, int index) {
-        var strv_length = this.get_strv_length (strv);
-        string[] slice = new string[strv_length - index];
-
-        for (int i = 0; i < slice.length; i++) {
-            slice[i] = strv[i + index];
-        }
-
-        return slice;
-    }
-
-    /**
-     * Gets the length of a null-terminated string array
-     *
-     * param strv the string to compute length of
-     *
-     * FIXME: Temporary hack, don't use once bug#571322 is fixed
-     */
-    private int get_strv_length (string[] strv) {
-        int i = 0;
-
-        for (i = 0; strv[i] != null; i++);
-
-        return i + 1;
-    }
-}
-