[evolution-data-server] Bug #727431 - Merge common factories' code into a superclass
- From: Fabiano Fidêncio <ffidencio src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Bug #727431 - Merge common factories' code into a superclass
- Date: Thu, 10 Apr 2014 02:15:05 +0000 (UTC)
commit d915f5c6fb19b0c6c388a4c0c85199bd6b5818c8
Author: Fabiano Fidêncio <fidencio redhat com>
Date: Mon Mar 17 02:40:13 2014 +0100
Bug #727431 - Merge common factories' code into a superclass
addressbook/libedata-book/e-book-backend-factory.c | 19 +-
addressbook/libedata-book/e-data-book-factory.c | 532 ++---------------
addressbook/libedata-book/e-data-book-factory.h | 3 -
addressbook/libedata-book/e-data-book.c | 8 +
calendar/libedata-cal/e-cal-backend-factory.c | 8 +-
calendar/libedata-cal/e-data-cal-factory.c | 647 +++-----------------
calendar/libedata-cal/e-data-cal-factory.h | 2 -
calendar/libedata-cal/e-data-cal.c | 8 +
configure.ac | 6 +-
docs/reference/eds/eds-sections.txt | 6 +-
libebackend/e-data-factory.c | 628 +++++++++++++++++++-
libebackend/e-data-factory.h | 26 +
libebackend/e-source-registry-server.c | 38 +-
13 files changed, 822 insertions(+), 1109 deletions(-)
---
diff --git a/addressbook/libedata-book/e-book-backend-factory.c
b/addressbook/libedata-book/e-book-backend-factory.c
index 296c13c..702dfbe 100644
--- a/addressbook/libedata-book/e-book-backend-factory.c
+++ b/addressbook/libedata-book/e-book-backend-factory.c
@@ -17,6 +17,7 @@
**/
#include <config.h>
+#include <string.h>
#include "e-book-backend.h"
#include "e-book-backend-factory.h"
@@ -41,15 +42,23 @@ static const gchar *
book_backend_factory_get_hash_key (EBackendFactory *factory)
{
EBookBackendFactoryClass *class;
+ const gchar *component_name;
+ gchar *hash_key;
+ gsize length;
class = E_BOOK_BACKEND_FACTORY_GET_CLASS (factory);
g_return_val_if_fail (class->factory_name != NULL, NULL);
- /* For address book backends the factory hash key is simply
- * the factory name. See ECalBackendFactory for a slightly
- * more complex scheme. */
+ component_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
- return class->factory_name;
+ /* Hash Key: FACTORY_NAME ':' COMPONENT_NAME */
+ length = strlen (class->factory_name) + strlen (component_name) + 2;
+ hash_key = g_alloca (length);
+ g_snprintf (
+ hash_key, length, "%s:%s",
+ class->factory_name, component_name);
+
+ return g_intern_string (hash_key);
}
static EBackend *
@@ -65,7 +74,7 @@ book_backend_factory_new_backend (EBackendFactory *factory,
class->backend_type, E_TYPE_BOOK_BACKEND), NULL);
data_factory = book_backend_factory_get_data_factory (factory);
- registry = e_data_book_factory_get_registry (data_factory);
+ registry = e_data_factory_get_registry (E_DATA_FACTORY (data_factory));
return g_object_new (
class->backend_type,
diff --git a/addressbook/libedata-book/e-data-book-factory.c b/addressbook/libedata-book/e-data-book-factory.c
index 96fb1d4..0d6bb95 100644
--- a/addressbook/libedata-book/e-data-book-factory.c
+++ b/addressbook/libedata-book/e-data-book-factory.c
@@ -51,19 +51,8 @@
((obj), E_TYPE_DATA_BOOK_FACTORY, EDataBookFactoryPrivate))
struct _EDataBookFactoryPrivate {
- ESourceRegistry *registry;
EDBusAddressBookFactory *dbus_factory;
- /* This is a hash table of client bus names to an array of
- * EBookBackend references; one for every connection opened. */
- GHashTable *connections;
- GMutex connections_lock;
-
- /* This is a hash table of client bus names being watched.
- * The value is the watcher ID for g_bus_unwatch_name(). */
- GHashTable *watched_names;
- GMutex watched_names_lock;
-
/* Watching "org.freedesktop.locale1" for locale changes */
guint localed_watch_id;
EDBusLocale1 *localed_proxy;
@@ -71,10 +60,7 @@ struct _EDataBookFactoryPrivate {
gchar *locale;
};
-enum {
- PROP_0,
- PROP_REGISTRY
-};
+static GInitableIface *initable_parent_interface;
/* Forward Declarations */
static void e_data_book_factory_initable_init
@@ -88,236 +74,14 @@ G_DEFINE_TYPE_WITH_CODE (
G_TYPE_INITABLE,
e_data_book_factory_initable_init))
-static void
-watched_names_value_free (gpointer value)
+static GDBusInterfaceSkeleton *
+data_book_factory_get_dbus_interface_skeleton (EDBusServer *server)
{
- g_bus_unwatch_name (GPOINTER_TO_UINT (value));
-}
-
-static void
-data_book_factory_toggle_notify_cb (gpointer data,
- GObject *backend,
- gboolean is_last_ref)
-{
- if (is_last_ref) {
- /* Take a strong reference before removing the
- * toggle reference, to keep the backend alive. */
- g_object_ref (backend);
-
- g_object_remove_toggle_ref (
- backend, data_book_factory_toggle_notify_cb, data);
-
- g_signal_emit_by_name (backend, "shutdown");
-
- g_object_unref (backend);
- }
-}
-
-static void
-data_book_factory_connections_add (EDataBookFactory *factory,
- const gchar *name,
- EBookBackend *backend)
-{
- GHashTable *connections;
- GPtrArray *array;
-
- g_return_if_fail (name != NULL);
- g_return_if_fail (backend != NULL);
-
- g_mutex_lock (&factory->priv->connections_lock);
-
- connections = factory->priv->connections;
-
- if (g_hash_table_size (connections) == 0)
- e_dbus_server_hold (E_DBUS_SERVER (factory));
-
- array = g_hash_table_lookup (connections, name);
-
- if (array == NULL) {
- array = g_ptr_array_new_with_free_func (
- (GDestroyNotify) g_object_unref);
- g_hash_table_insert (
- connections, g_strdup (name), array);
- }
-
- g_ptr_array_add (array, g_object_ref (backend));
-
- g_mutex_unlock (&factory->priv->connections_lock);
-}
-
-static gboolean
-data_book_factory_connections_remove (EDataBookFactory *factory,
- const gchar *name,
- EBookBackend *backend)
-{
- GHashTable *connections;
- GPtrArray *array;
- gboolean removed = FALSE;
-
- /* If backend is NULL, we remove all backends for name. */
- g_return_val_if_fail (name != NULL, FALSE);
-
- g_mutex_lock (&factory->priv->connections_lock);
-
- connections = factory->priv->connections;
- array = g_hash_table_lookup (connections, name);
-
- if (array != NULL) {
- if (backend != NULL) {
- removed = g_ptr_array_remove_fast (array, backend);
- } else if (array->len > 0) {
- g_ptr_array_set_size (array, 0);
- removed = TRUE;
- }
-
- if (array->len == 0)
- g_hash_table_remove (connections, name);
-
- if (g_hash_table_size (connections) == 0)
- e_dbus_server_release (E_DBUS_SERVER (factory));
- }
-
- g_mutex_unlock (&factory->priv->connections_lock);
-
- return removed;
-}
-
-static void
-data_book_factory_connections_remove_all (EDataBookFactory *factory)
-{
- GHashTable *connections;
-
- g_mutex_lock (&factory->priv->connections_lock);
-
- connections = factory->priv->connections;
-
- if (g_hash_table_size (connections) > 0) {
- g_hash_table_remove_all (connections);
- e_dbus_server_release (E_DBUS_SERVER (factory));
- }
-
- g_mutex_unlock (&factory->priv->connections_lock);
-}
-
-static void
-data_book_factory_name_vanished_cb (GDBusConnection *connection,
- const gchar *name,
- gpointer user_data)
-{
- GWeakRef *weak_ref = user_data;
EDataBookFactory *factory;
- factory = g_weak_ref_get (weak_ref);
-
- if (factory != NULL) {
- data_book_factory_connections_remove (factory, name, NULL);
-
- /* Unwatching the bus name from here will corrupt the
- * 'name' argument, and possibly also the 'user_data'.
- *
- * This is a GDBus bug. Work around it by unwatching
- * the bus name last.
- *
- * See: https://bugzilla.gnome.org/706088
- */
- g_mutex_lock (&factory->priv->watched_names_lock);
- g_hash_table_remove (factory->priv->watched_names, name);
- g_mutex_unlock (&factory->priv->watched_names_lock);
-
- g_object_unref (factory);
- }
-}
-
-static void
-data_book_factory_watched_names_add (EDataBookFactory *factory,
- GDBusConnection *connection,
- const gchar *name)
-{
- GHashTable *watched_names;
-
- g_return_if_fail (name != NULL);
-
- g_mutex_lock (&factory->priv->watched_names_lock);
-
- watched_names = factory->priv->watched_names;
-
- if (!g_hash_table_contains (watched_names, name)) {
- guint watcher_id;
-
- /* The g_bus_watch_name() documentation says one of the two
- * callbacks are guaranteed to be invoked after calling the
- * function. But which one is determined asynchronously so
- * there should be no chance of the name vanished callback
- * deadlocking with us when it tries to acquire the lock. */
- watcher_id = g_bus_watch_name_on_connection (
- connection, name,
- G_BUS_NAME_WATCHER_FLAGS_NONE,
- (GBusNameAppearedCallback) NULL,
- data_book_factory_name_vanished_cb,
- e_weak_ref_new (factory),
- (GDestroyNotify) e_weak_ref_free);
-
- g_hash_table_insert (
- watched_names, g_strdup (name),
- GUINT_TO_POINTER (watcher_id));
- }
-
- g_mutex_unlock (&factory->priv->watched_names_lock);
-}
-
-static EBackend *
-data_book_factory_ref_backend (EDataFactory *factory,
- ESource *source,
- GError **error)
-{
- EBackend *backend;
- ESourceBackend *extension;
- const gchar *extension_name;
- gchar *backend_name;
-
- /* For address books the hash key is simply the backend name.
- * (cf. calendar hash keys, which are slightly more complex) */
-
- extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
- extension = e_source_get_extension (source, extension_name);
- backend_name = e_source_backend_dup_backend_name (extension);
-
- if (backend_name == NULL || *backend_name == '\0') {
- g_set_error (
- error, E_DATA_BOOK_ERROR,
- E_DATA_BOOK_STATUS_NO_SUCH_BOOK,
- _("No backend name in source '%s'"),
- e_source_get_display_name (source));
- g_free (backend_name);
- return NULL;
- }
-
- backend = e_data_factory_ref_initable_backend (
- factory, backend_name, source, NULL, error);
-
- g_free (backend_name);
-
- return backend;
-}
-
-static gchar *
-construct_book_factory_path (void)
-{
- static volatile gint counter = 1;
-
- g_atomic_int_inc (&counter);
-
- return g_strdup_printf (
- "/org/gnome/evolution/dataserver/AddressBook/%d/%u",
- getpid (), counter);
-}
+ factory = E_DATA_BOOK_FACTORY (server);
-static void
-data_book_factory_closed_cb (EBookBackend *backend,
- const gchar *sender,
- EDataBookFactory *factory)
-{
- data_book_factory_connections_remove (factory, sender, backend);
+ return G_DBUS_INTERFACE_SKELETON (factory->priv->dbus_factory);
}
/* This is totally backwards, for some insane reason we holding
@@ -329,74 +93,33 @@ static GList *
data_book_factory_list_books (EDataBookFactory *factory)
{
GList *books = NULL;
- GHashTable *connections;
- GHashTableIter iter;
- gpointer key, value;
+ GSList *backends, *l;
- g_mutex_lock (&factory->priv->connections_lock);
+ backends = e_data_factory_list_backends (E_DATA_FACTORY (factory));
- connections = factory->priv->connections;
+ for (l = backends; l != NULL; l = g_slist_next (l)); {
+ EBookBackend *backend = l->data;
+ EDataBook *book = e_book_backend_ref_data_book (backend);
- g_hash_table_iter_init (&iter, connections);
- while (g_hash_table_iter_next (&iter, &key, &value)) {
- GPtrArray *array = (GPtrArray *) value;
- gint i;
-
- for (i = 0; i < array->len; i++) {
- EBookBackend *backend = g_ptr_array_index (array, i);
- EDataBook *book = e_book_backend_ref_data_book (backend);
-
- if (g_list_find (books, book) == NULL)
- books = g_list_prepend (books, book);
- else
- g_object_unref (book);
- }
+ if (g_list_find (books, book) == NULL)
+ books = g_list_prepend (books, book);
+ else
+ g_object_unref (book);
}
- g_mutex_unlock (&factory->priv->connections_lock);
return books;
}
static gchar *
-data_book_factory_open (EDataBookFactory *factory,
- GDBusConnection *connection,
- const gchar *sender,
- const gchar *uid,
- GError **error)
+data_book_factory_open (EDataFactory *data_factory,
+ EBackend *backend,
+ GDBusConnection *connection,
+ GError **error)
{
+ EDataBookFactory *factory = E_DATA_BOOK_FACTORY (data_factory);
EDataBook *data_book;
- EBackend *backend;
- ESourceRegistry *registry;
- ESource *source;
gchar *object_path;
- if (uid == NULL || *uid == '\0') {
- g_set_error (
- error, E_DATA_BOOK_ERROR,
- E_DATA_BOOK_STATUS_NO_SUCH_BOOK,
- _("Missing source UID"));
- return NULL;
- }
-
- registry = e_data_book_factory_get_registry (factory);
- source = e_source_registry_ref_source (registry, uid);
-
- if (source == NULL) {
- g_set_error (
- error, E_DATA_BOOK_ERROR,
- E_DATA_BOOK_STATUS_NO_SUCH_BOOK,
- _("No such source for UID '%s'"), uid);
- return NULL;
- }
-
- backend = data_book_factory_ref_backend (
- E_DATA_FACTORY (factory), source, error);
-
- g_object_unref (source);
-
- if (backend == NULL)
- return NULL;
-
/* If the backend already has an EDataBook installed, return its
* object path. Otherwise we need to install a new EDataBook. */
@@ -406,7 +129,7 @@ data_book_factory_open (EDataBookFactory *factory,
object_path = g_strdup (
e_data_book_get_object_path (data_book));
} else {
- object_path = construct_book_factory_path ();
+ object_path = e_data_factory_construct_path (data_factory);
/* The EDataBook will attach itself to EBookBackend,
* so no need to call e_book_backend_set_data_book(). */
@@ -415,18 +138,8 @@ data_book_factory_open (EDataBookFactory *factory,
connection, object_path, error);
if (data_book != NULL) {
- /* Install a toggle reference on the backend
- * so we can signal it to shut down once all
- * client connections are closed. */
- g_object_add_toggle_ref (
- G_OBJECT (backend),
- data_book_factory_toggle_notify_cb,
- NULL);
-
- g_signal_connect_object (
- backend, "closed",
- G_CALLBACK (data_book_factory_closed_cb),
- factory, 0);
+ e_data_factory_set_backend_callbacks (
+ data_factory, backend);
/* Don't set the locale on a new book if we have not
* yet received a notification of a locale change
@@ -442,21 +155,7 @@ data_book_factory_open (EDataBookFactory *factory,
}
}
- if (data_book != NULL) {
- /* Watch the sender's bus name so we can clean
- * up its connections if the bus name vanishes. */
- data_book_factory_watched_names_add (
- factory, connection, sender);
-
- /* A client may create multiple EClient instances for the
- * same ESource, each of which calls close() individually.
- * So we must track each and every connection made. */
- data_book_factory_connections_add (
- factory, sender, E_BOOK_BACKEND (backend));
- }
-
g_clear_object (&data_book);
- g_clear_object (&backend);
return object_path;
}
@@ -475,8 +174,9 @@ data_book_factory_handle_open_address_book_cb (EDBusAddressBookFactory *iface,
connection = g_dbus_method_invocation_get_connection (invocation);
sender = g_dbus_method_invocation_get_sender (invocation);
- object_path = data_book_factory_open (
- factory, connection, sender, uid, &error);
+ object_path = e_data_factory_open_backend (
+ E_DATA_FACTORY (factory), connection, sender,
+ uid, E_SOURCE_EXTENSION_ADDRESS_BOOK, &error);
if (object_path != NULL) {
e_dbus_address_book_factory_complete_open_address_book (
@@ -491,57 +191,25 @@ data_book_factory_handle_open_address_book_cb (EDBusAddressBookFactory *iface,
}
static void
-data_book_factory_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec)
-{
- switch (property_id) {
- case PROP_REGISTRY:
- g_value_set_object (
- value,
- e_data_book_factory_get_registry (
- E_DATA_BOOK_FACTORY (object)));
- return;
- }
-
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-}
-
-static void
data_book_factory_dispose (GObject *object)
{
+ EDataBookFactory *factory;
EDataBookFactoryPrivate *priv;
- priv = E_DATA_BOOK_FACTORY_GET_PRIVATE (object);
+ factory = E_DATA_BOOK_FACTORY (object);
+ priv = factory->priv;
- if (priv->registry != NULL) {
- g_object_unref (priv->registry);
- priv->registry = NULL;
- }
+ g_clear_object (&priv->dbus_factory);
- if (priv->dbus_factory != NULL) {
- g_object_unref (priv->dbus_factory);
- priv->dbus_factory = NULL;
- }
-
- if (priv->localed_cancel) {
+ if (priv->localed_cancel)
g_cancellable_cancel (priv->localed_cancel);
- g_object_unref (priv->localed_cancel);
- priv->localed_cancel = NULL;
- }
- if (priv->localed_proxy) {
- g_object_unref (priv->localed_proxy);
- priv->localed_proxy = NULL;
- }
+ g_clear_object (&priv->localed_cancel);
+ g_clear_object (&priv->localed_proxy);
if (priv->localed_watch_id > 0)
g_bus_unwatch_name (priv->localed_watch_id);
- g_hash_table_remove_all (priv->connections);
- g_hash_table_remove_all (priv->watched_names);
-
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_data_book_factory_parent_class)->dispose (object);
}
@@ -549,80 +217,16 @@ data_book_factory_dispose (GObject *object)
static void
data_book_factory_finalize (GObject *object)
{
- EDataBookFactoryPrivate *priv;
-
- priv = E_DATA_BOOK_FACTORY_GET_PRIVATE (object);
-
- g_hash_table_destroy (priv->connections);
- g_mutex_clear (&priv->connections_lock);
+ EDataBookFactory *factory;
- g_hash_table_destroy (priv->watched_names);
- g_mutex_clear (&priv->watched_names_lock);
+ factory = E_DATA_BOOK_FACTORY (object);
- g_free (priv->locale);
+ g_free (factory->priv->locale);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_data_book_factory_parent_class)->finalize (object);
}
-static void
-data_book_factory_bus_acquired (EDBusServer *server,
- GDBusConnection *connection)
-{
- EDataBookFactoryPrivate *priv;
- GError *error = NULL;
-
- priv = E_DATA_BOOK_FACTORY_GET_PRIVATE (server);
-
- g_dbus_interface_skeleton_export (
- G_DBUS_INTERFACE_SKELETON (priv->dbus_factory),
- connection,
- "/org/gnome/evolution/dataserver/AddressBookFactory",
- &error);
-
- if (error != NULL) {
- g_error (
- "Failed to export AddressBookFactory interface: %s",
- error->message);
- g_assert_not_reached ();
- }
-
- /* Chain up to parent's bus_acquired() method. */
- E_DBUS_SERVER_CLASS (e_data_book_factory_parent_class)->
- bus_acquired (server, connection);
-}
-
-static void
-data_book_factory_bus_name_lost (EDBusServer *server,
- GDBusConnection *connection)
-{
- EDataBookFactory *factory;
-
- factory = E_DATA_BOOK_FACTORY (server);
-
- data_book_factory_connections_remove_all (factory);
-
- /* Chain up to parent's bus_name_lost() method. */
- E_DBUS_SERVER_CLASS (e_data_book_factory_parent_class)->
- bus_name_lost (server, connection);
-}
-
-static void
-data_book_factory_quit_server (EDBusServer *server,
- EDBusServerExitCode exit_code)
-{
- /* This factory does not support reloading, so stop the signal
- * emission and return without chaining up to prevent quitting. */
- if (exit_code == E_DBUS_SERVER_EXIT_RELOAD) {
- g_signal_stop_emission_by_name (server, "quit-server");
- return;
- }
-
- /* Chain up to parent's quit_server() method. */
- E_DBUS_SERVER_CLASS (e_data_book_factory_parent_class)->
- quit_server (server, exit_code);
-}
-
static gchar *
data_book_factory_interpret_locale_value (const gchar *value)
{
@@ -797,12 +401,10 @@ data_book_factory_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
- EDataBookFactoryPrivate *priv;
+ EDataBookFactory *factory;
GBusType bus_type = G_BUS_TYPE_SYSTEM;
- priv = E_DATA_BOOK_FACTORY_GET_PRIVATE (initable);
-
- priv->registry = e_source_registry_new_sync (cancellable, error);
+ factory = E_DATA_BOOK_FACTORY (initable);
/* When running tests, we pretend to be the "org.freedesktop.locale1" service
* on the session bus instead of the real location on the system bus.
@@ -811,7 +413,7 @@ data_book_factory_initable_init (GInitable *initable,
bus_type = G_BUS_TYPE_SESSION;
/* Watch system bus for locale change notifications */
- priv->localed_watch_id =
+ factory->priv->localed_watch_id =
g_bus_watch_name (
bus_type,
"org.freedesktop.locale1",
@@ -821,7 +423,8 @@ data_book_factory_initable_init (GInitable *initable,
initable,
NULL);
- return (priv->registry != NULL);
+ /* Chain up to parent interface's init() method. */
+ return initable_parent_interface->init (initable, cancellable, error);
}
static void
@@ -841,35 +444,26 @@ e_data_book_factory_class_init (EDataBookFactoryClass *class)
g_type_class_add_private (class, sizeof (EDataBookFactoryPrivate));
object_class = G_OBJECT_CLASS (class);
- object_class->get_property = data_book_factory_get_property;
object_class->dispose = data_book_factory_dispose;
object_class->finalize = data_book_factory_finalize;
dbus_server_class = E_DBUS_SERVER_CLASS (class);
dbus_server_class->bus_name = ADDRESS_BOOK_DBUS_SERVICE_NAME;
dbus_server_class->module_directory = modules_directory;
- dbus_server_class->bus_acquired = data_book_factory_bus_acquired;
- dbus_server_class->bus_name_lost = data_book_factory_bus_name_lost;
- dbus_server_class->quit_server = data_book_factory_quit_server;
data_factory_class = E_DATA_FACTORY_CLASS (class);
data_factory_class->backend_factory_type = E_TYPE_BOOK_BACKEND_FACTORY;
-
- g_object_class_install_property (
- object_class,
- PROP_REGISTRY,
- g_param_spec_object (
- "registry",
- "Registry",
- "Data source registry",
- E_TYPE_SOURCE_REGISTRY,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
+ data_factory_class->factory_object_path = "/org/gnome/evolution/dataserver/AddressBookFactory";
+ data_factory_class->data_object_path_prefix = "/org/gnome/evolution/dataserver/Addressbook";
+ data_factory_class->get_dbus_interface_skeleton = data_book_factory_get_dbus_interface_skeleton;
+ data_factory_class->data_open = data_book_factory_open;
}
static void
e_data_book_factory_initable_init (GInitableIface *iface)
{
+ initable_parent_interface = g_type_interface_peek_parent (iface);
+
iface->init = data_book_factory_initable_init;
}
@@ -885,21 +479,6 @@ e_data_book_factory_init (EDataBookFactory *factory)
factory->priv->dbus_factory, "handle-open-address-book",
G_CALLBACK (data_book_factory_handle_open_address_book_cb),
factory);
-
- factory->priv->connections = g_hash_table_new_full (
- (GHashFunc) g_str_hash,
- (GEqualFunc) g_str_equal,
- (GDestroyNotify) g_free,
- (GDestroyNotify) g_ptr_array_unref);
-
- g_mutex_init (&factory->priv->connections_lock);
- g_mutex_init (&factory->priv->watched_names_lock);
-
- factory->priv->watched_names = g_hash_table_new_full (
- (GHashFunc) g_str_hash,
- (GEqualFunc) g_str_equal,
- (GDestroyNotify) g_free,
- (GDestroyNotify) watched_names_value_free);
}
EDBusServer *
@@ -910,22 +489,3 @@ e_data_book_factory_new (GCancellable *cancellable,
E_TYPE_DATA_BOOK_FACTORY,
cancellable, error, NULL);
}
-
-/**
- * e_data_book_factory_get_registry:
- * @factory: an #EDataBookFactory
- *
- * Returns the #ESourceRegistry owned by @factory.
- *
- * Returns: the #ESourceRegistry
- *
- * Since: 3.6
- **/
-ESourceRegistry *
-e_data_book_factory_get_registry (EDataBookFactory *factory)
-{
- g_return_val_if_fail (E_IS_DATA_BOOK_FACTORY (factory), NULL);
-
- return factory->priv->registry;
-}
-
diff --git a/addressbook/libedata-book/e-data-book-factory.h b/addressbook/libedata-book/e-data-book-factory.h
index 80990a9..9c515c3 100644
--- a/addressbook/libedata-book/e-data-book-factory.h
+++ b/addressbook/libedata-book/e-data-book-factory.h
@@ -71,9 +71,6 @@ struct _EDataBookFactoryClass {
GType e_data_book_factory_get_type (void) G_GNUC_CONST;
EDBusServer * e_data_book_factory_new (GCancellable *cancellable,
GError **error);
-ESourceRegistry *
- e_data_book_factory_get_registry
- (EDataBookFactory *factory);
G_END_DECLS
diff --git a/addressbook/libedata-book/e-data-book.c b/addressbook/libedata-book/e-data-book.c
index 26986dc..f197916 100644
--- a/addressbook/libedata-book/e-data-book.c
+++ b/addressbook/libedata-book/e-data-book.c
@@ -235,6 +235,14 @@ data_book_convert_to_client_error (GError *error)
{
g_return_if_fail (error != NULL);
+ /* Data-Factory returns common error for unknown/broken ESource-s */
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
+ error->domain = E_BOOK_CLIENT_ERROR;
+ error->code = E_BOOK_CLIENT_ERROR_NO_SUCH_BOOK;
+
+ return;
+ }
+
if (error->domain != E_DATA_BOOK_ERROR)
return;
diff --git a/calendar/libedata-cal/e-cal-backend-factory.c b/calendar/libedata-cal/e-cal-backend-factory.c
index 30d1a8e..48b1d8d 100644
--- a/calendar/libedata-cal/e-cal-backend-factory.c
+++ b/calendar/libedata-cal/e-cal-backend-factory.c
@@ -51,13 +51,13 @@ cal_backend_factory_get_hash_key (EBackendFactory *factory)
switch (class->component_kind) {
case ICAL_VEVENT_COMPONENT:
- component_name = "VEVENT";
+ component_name = E_SOURCE_EXTENSION_CALENDAR;
break;
case ICAL_VTODO_COMPONENT:
- component_name = "VTODO";
+ component_name = E_SOURCE_EXTENSION_TASK_LIST;
break;
case ICAL_VJOURNAL_COMPONENT:
- component_name = "VJOURNAL";
+ component_name = E_SOURCE_EXTENSION_MEMO_LIST;
break;
default:
g_return_val_if_reached (NULL);
@@ -86,7 +86,7 @@ cal_backend_factory_new_backend (EBackendFactory *factory,
class->backend_type, E_TYPE_CAL_BACKEND), NULL);
data_factory = cal_backend_factory_get_data_factory (factory);
- registry = e_data_cal_factory_get_registry (data_factory);
+ registry = e_data_factory_get_registry (E_DATA_FACTORY (data_factory));
return g_object_new (
class->backend_type,
diff --git a/calendar/libedata-cal/e-data-cal-factory.c b/calendar/libedata-cal/e-data-cal-factory.c
index eb34085..a3d57f1 100644
--- a/calendar/libedata-cal/e-data-cal-factory.c
+++ b/calendar/libedata-cal/e-data-cal-factory.c
@@ -56,24 +56,10 @@
((obj), E_TYPE_DATA_CAL_FACTORY, EDataCalFactoryPrivate))
struct _EDataCalFactoryPrivate {
- ESourceRegistry *registry;
EDBusCalendarFactory *dbus_factory;
-
- /* This is a hash table of client bus names to an array of
- * ECalBackend references; one for every connection opened. */
- GHashTable *connections;
- GMutex connections_lock;
-
- /* This is a hash table of client bus names being watched.
- * The value is the watcher ID for g_bus_unwatch_name(). */
- GHashTable *watched_names;
- GMutex watched_names_lock;
};
-enum {
- PROP_0,
- PROP_REGISTRY
-};
+static GInitableIface *initable_parent_interface;
/* Forward Declarations */
static void e_data_cal_factory_initable_init
@@ -87,278 +73,25 @@ G_DEFINE_TYPE_WITH_CODE (
G_TYPE_INITABLE,
e_data_cal_factory_initable_init))
-static void
-watched_names_value_free (gpointer value)
-{
- g_bus_unwatch_name (GPOINTER_TO_UINT (value));
-}
-
-static void
-data_cal_factory_toggle_notify_cb (gpointer data,
- GObject *backend,
- gboolean is_last_ref)
-{
- if (is_last_ref) {
- /* Take a strong reference before removing the
- * toggle reference, to keep the backend alive. */
- g_object_ref (backend);
-
- g_object_remove_toggle_ref (
- backend, data_cal_factory_toggle_notify_cb, data);
-
- g_signal_emit_by_name (backend, "shutdown");
-
- g_object_unref (backend);
- }
-}
-
-static void
-data_cal_factory_connections_add (EDataCalFactory *factory,
- const gchar *name,
- ECalBackend *backend)
-{
- GHashTable *connections;
- GPtrArray *array;
-
- g_return_if_fail (name != NULL);
- g_return_if_fail (backend != NULL);
-
- g_mutex_lock (&factory->priv->connections_lock);
-
- connections = factory->priv->connections;
-
- if (g_hash_table_size (connections) == 0)
- e_dbus_server_hold (E_DBUS_SERVER (factory));
-
- array = g_hash_table_lookup (connections, name);
-
- if (array == NULL) {
- array = g_ptr_array_new_with_free_func (
- (GDestroyNotify) g_object_unref);
- g_hash_table_insert (
- connections, g_strdup (name), array);
- }
-
- g_ptr_array_add (array, g_object_ref (backend));
-
- g_mutex_unlock (&factory->priv->connections_lock);
-}
-
-static gboolean
-data_cal_factory_connections_remove (EDataCalFactory *factory,
- const gchar *name,
- ECalBackend *backend)
+static GDBusInterfaceSkeleton *
+data_cal_factory_get_dbus_interface_skeleton (EDBusServer *server)
{
- GHashTable *connections;
- GPtrArray *array;
- gboolean removed = FALSE;
-
- /* If backend is NULL, we remove all backends for name. */
- g_return_val_if_fail (name != NULL, FALSE);
-
- g_mutex_lock (&factory->priv->connections_lock);
-
- connections = factory->priv->connections;
- array = g_hash_table_lookup (connections, name);
-
- if (array != NULL) {
- if (backend != NULL) {
- removed = g_ptr_array_remove_fast (array, backend);
- } else if (array->len > 0) {
- g_ptr_array_set_size (array, 0);
- removed = TRUE;
- }
-
- if (array->len == 0)
- g_hash_table_remove (connections, name);
-
- if (g_hash_table_size (connections) == 0)
- e_dbus_server_release (E_DBUS_SERVER (factory));
- }
-
- g_mutex_unlock (&factory->priv->connections_lock);
-
- return removed;
-}
-
-static void
-data_cal_factory_connections_remove_all (EDataCalFactory *factory)
-{
- GHashTable *connections;
-
- g_mutex_lock (&factory->priv->connections_lock);
-
- connections = factory->priv->connections;
-
- if (g_hash_table_size (connections) > 0) {
- g_hash_table_remove_all (connections);
- e_dbus_server_release (E_DBUS_SERVER (factory));
- }
-
- g_mutex_unlock (&factory->priv->connections_lock);
-}
-
-static void
-data_cal_factory_name_vanished_cb (GDBusConnection *connection,
- const gchar *name,
- gpointer user_data)
-{
- GWeakRef *weak_ref = user_data;
EDataCalFactory *factory;
- factory = g_weak_ref_get (weak_ref);
-
- if (factory != NULL) {
- data_cal_factory_connections_remove (factory, name, NULL);
-
- /* Unwatching the bus name from here will corrupt the
- * 'name' argument, and possibly also the 'user_data'.
- *
- * This is a GDBus bug. Work around it by unwatching
- * the bus name last.
- *
- * See: https://bugzilla.gnome.org/706088
- */
- g_mutex_lock (&factory->priv->watched_names_lock);
- g_hash_table_remove (factory->priv->watched_names, name);
- g_mutex_unlock (&factory->priv->watched_names_lock);
-
- g_object_unref (factory);
- }
-}
-
-static void
-data_cal_factory_watched_names_add (EDataCalFactory *factory,
- GDBusConnection *connection,
- const gchar *name)
-{
- GHashTable *watched_names;
-
- g_return_if_fail (name != NULL);
-
- g_mutex_lock (&factory->priv->watched_names_lock);
-
- watched_names = factory->priv->watched_names;
-
- if (!g_hash_table_contains (watched_names, name)) {
- guint watcher_id;
-
- /* The g_bus_watch_name() documentation says one of the two
- * callbacks are guaranteed to be invoked after calling the
- * function. But which one is determined asynchronously so
- * there should be no chance of the name vanished callback
- * deadlocking with us when it tries to acquire the lock. */
- watcher_id = g_bus_watch_name_on_connection (
- connection, name,
- G_BUS_NAME_WATCHER_FLAGS_NONE,
- (GBusNameAppearedCallback) NULL,
- data_cal_factory_name_vanished_cb,
- e_weak_ref_new (factory),
- (GDestroyNotify) e_weak_ref_free);
-
- g_hash_table_insert (
- watched_names, g_strdup (name),
- GUINT_TO_POINTER (watcher_id));
- }
-
- g_mutex_unlock (&factory->priv->watched_names_lock);
-}
-
-static EBackend *
-data_cal_factory_ref_backend (EDataFactory *factory,
- ESource *source,
- const gchar *extension_name,
- const gchar *type_string,
- GError **error)
-{
- EBackend *backend;
- ESourceBackend *extension;
- gchar *backend_name;
- gchar *hash_key;
-
- extension = e_source_get_extension (source, extension_name);
- backend_name = e_source_backend_dup_backend_name (extension);
-
- if (backend_name == NULL || *backend_name == '\0') {
- g_set_error (
- error, E_DATA_CAL_ERROR, NoSuchCal,
- _("No backend name in source '%s'"),
- e_source_get_display_name (source));
- g_free (backend_name);
- return NULL;
- }
-
- hash_key = g_strdup_printf ("%s:%s", backend_name, type_string);
- backend = e_data_factory_ref_initable_backend (
- factory, hash_key, source, NULL, error);
- g_free (hash_key);
-
- g_free (backend_name);
-
- return backend;
-}
-
-static gchar *
-construct_cal_factory_path (void)
-{
- static volatile gint counter = 1;
-
- g_atomic_int_inc (&counter);
-
- return g_strdup_printf (
- "/org/gnome/evolution/dataserver/Calendar/%d/%u",
- getpid (), counter);
-}
+ factory = E_DATA_CAL_FACTORY (server);
-static void
-data_cal_factory_closed_cb (ECalBackend *backend,
- const gchar *sender,
- EDataCalFactory *factory)
-{
- data_cal_factory_connections_remove (factory, sender, backend);
+ return G_DBUS_INTERFACE_SKELETON (factory->priv->dbus_factory);
}
static gchar *
-data_cal_factory_open (EDataCalFactory *factory,
- GDBusConnection *connection,
- const gchar *sender,
- const gchar *uid,
- const gchar *extension_name,
- const gchar *type_string,
- GError **error)
+data_cal_factory_open (EDataFactory *data_factory,
+ EBackend *backend,
+ GDBusConnection *connection,
+ GError **error)
{
EDataCal *data_cal;
- EBackend *backend;
- ESourceRegistry *registry;
- ESource *source;
gchar *object_path;
- if (uid == NULL || *uid == '\0') {
- g_set_error (
- error, E_DATA_CAL_ERROR, NoSuchCal,
- _("Missing source UID"));
- return NULL;
- }
-
- registry = e_data_cal_factory_get_registry (factory);
- source = e_source_registry_ref_source (registry, uid);
-
- if (source == NULL) {
- g_set_error (
- error, E_DATA_CAL_ERROR, NoSuchCal,
- _("No such source for UID '%s'"), uid);
- return NULL;
- }
-
- backend = data_cal_factory_ref_backend (
- E_DATA_FACTORY (factory), source,
- extension_name, type_string, error);
-
- g_object_unref (source);
-
- if (backend == NULL)
- return NULL;
-
/* If the backend already has an EDataCal installed, return its
* object path. Otherwise we need to install a new EDataCal. */
@@ -368,7 +101,7 @@ data_cal_factory_open (EDataCalFactory *factory,
object_path = g_strdup (
e_data_cal_get_object_path (data_cal));
} else {
- object_path = construct_cal_factory_path ();
+ object_path = e_data_factory_construct_path (data_factory);
/* The EDataCal will attach itself to ECalBackend,
* so no need to call e_cal_backend_set_data_cal(). */
@@ -377,270 +110,39 @@ data_cal_factory_open (EDataCalFactory *factory,
connection, object_path, error);
if (data_cal != NULL) {
- /* Install a toggle reference on the backend
- * so we can signal it to shut down once all
- * client connections are closed. */
- g_object_add_toggle_ref (
- G_OBJECT (backend),
- data_cal_factory_toggle_notify_cb,
- NULL);
-
- g_signal_connect_object (
- backend, "closed",
- G_CALLBACK (data_cal_factory_closed_cb),
- factory, 0);
-
+ e_data_factory_set_backend_callbacks (
+ data_factory, backend);
} else {
g_free (object_path);
object_path = NULL;
}
}
- if (data_cal != NULL) {
- /* Watch the sender's bus name so we can clean
- * up its connections if the bus name vanishes. */
- data_cal_factory_watched_names_add (
- factory, connection, sender);
-
- /* A client may create multiple EClient instances for the
- * same ESource, each of which calls close() individually.
- * So we must track each and every connection made. */
- data_cal_factory_connections_add (
- factory, sender, E_CAL_BACKEND (backend));
-
- g_object_unref (data_cal);
- }
-
- g_object_unref (backend);
+ g_clear_object (&data_cal);
return object_path;
}
static gboolean
-data_cal_factory_handle_open_calendar_cb (EDBusCalendarFactory *dbus_interface,
- GDBusMethodInvocation *invocation,
- const gchar *uid,
- EDataCalFactory *factory)
-{
- GDBusConnection *connection;
- const gchar *sender;
- gchar *object_path;
- GError *error = NULL;
-
- connection = g_dbus_method_invocation_get_connection (invocation);
- sender = g_dbus_method_invocation_get_sender (invocation);
-
- object_path = data_cal_factory_open (
- factory, connection, sender, uid,
- E_SOURCE_EXTENSION_CALENDAR, "VEVENT", &error);
-
- if (object_path != NULL) {
- e_dbus_calendar_factory_complete_open_calendar (
- dbus_interface, invocation, object_path);
- g_free (object_path);
- } else {
- g_return_val_if_fail (error != NULL, FALSE);
- g_dbus_method_invocation_take_error (invocation, error);
- }
-
- return TRUE;
-}
-
-static gboolean
-data_cal_factory_handle_open_task_list_cb (EDBusCalendarFactory *dbus_interface,
- GDBusMethodInvocation *invocation,
- const gchar *uid,
- EDataCalFactory *factory)
-{
- GDBusConnection *connection;
- const gchar *sender;
- gchar *object_path;
- GError *error = NULL;
-
- connection = g_dbus_method_invocation_get_connection (invocation);
- sender = g_dbus_method_invocation_get_sender (invocation);
-
- object_path = data_cal_factory_open (
- factory, connection, sender, uid,
- E_SOURCE_EXTENSION_TASK_LIST, "VTODO", &error);
-
- if (object_path != NULL) {
- e_dbus_calendar_factory_complete_open_task_list (
- dbus_interface, invocation, object_path);
- g_free (object_path);
- } else {
- g_return_val_if_fail (error != NULL, FALSE);
- g_dbus_method_invocation_take_error (invocation, error);
- }
-
- return TRUE;
-}
-
-static gboolean
-data_cal_factory_handle_open_memo_list_cb (EDBusCalendarFactory *dbus_interface,
- GDBusMethodInvocation *invocation,
- const gchar *uid,
- EDataCalFactory *factory)
-{
- GDBusConnection *connection;
- const gchar *sender;
- gchar *object_path;
- GError *error = NULL;
-
- connection = g_dbus_method_invocation_get_connection (invocation);
- sender = g_dbus_method_invocation_get_sender (invocation);
-
- object_path = data_cal_factory_open (
- factory, connection, sender, uid,
- E_SOURCE_EXTENSION_MEMO_LIST, "VJOURNAL", &error);
-
- if (object_path != NULL) {
- e_dbus_calendar_factory_complete_open_memo_list (
- dbus_interface, invocation, object_path);
- g_free (object_path);
- } else {
- g_return_val_if_fail (error != NULL, FALSE);
- g_dbus_method_invocation_take_error (invocation, error);
- }
-
- return TRUE;
-}
-
-static void
-data_cal_factory_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec)
-{
- switch (property_id) {
- case PROP_REGISTRY:
- g_value_set_object (
- value,
- e_data_cal_factory_get_registry (
- E_DATA_CAL_FACTORY (object)));
- return;
- }
-
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-}
-
-static void
-data_cal_factory_dispose (GObject *object)
-{
- EDataCalFactoryPrivate *priv;
-
- priv = E_DATA_CAL_FACTORY_GET_PRIVATE (object);
-
- if (priv->registry != NULL) {
- g_object_unref (priv->registry);
- priv->registry = NULL;
- }
-
- if (priv->dbus_factory != NULL) {
- g_object_unref (priv->dbus_factory);
- priv->dbus_factory = NULL;
- }
-
- g_hash_table_remove_all (priv->connections);
- g_hash_table_remove_all (priv->watched_names);
-
- /* Chain up to parent's dispose() method. */
- G_OBJECT_CLASS (e_data_cal_factory_parent_class)->dispose (object);
-}
-
-static void
-data_cal_factory_finalize (GObject *object)
-{
- EDataCalFactoryPrivate *priv;
-
- priv = E_DATA_CAL_FACTORY_GET_PRIVATE (object);
-
- g_hash_table_destroy (priv->connections);
- g_mutex_clear (&priv->connections_lock);
-
- g_hash_table_destroy (priv->watched_names);
- g_mutex_clear (&priv->watched_names_lock);
-
- /* Chain up to parent's finalize() method. */
- G_OBJECT_CLASS (e_data_cal_factory_parent_class)->finalize (object);
-}
-
-static void
-data_cal_factory_bus_acquired (EDBusServer *server,
- GDBusConnection *connection)
-{
- EDataCalFactoryPrivate *priv;
- GError *error = NULL;
-
- priv = E_DATA_CAL_FACTORY_GET_PRIVATE (server);
-
- g_dbus_interface_skeleton_export (
- G_DBUS_INTERFACE_SKELETON (priv->dbus_factory),
- connection,
- "/org/gnome/evolution/dataserver/CalendarFactory",
- &error);
-
- if (error != NULL) {
- g_error (
- "Failed to export CalendarFactory interface: %s",
- error->message);
- g_assert_not_reached ();
- }
-
- /* Chain up to parent's bus_acquired() method. */
- E_DBUS_SERVER_CLASS (e_data_cal_factory_parent_class)->
- bus_acquired (server, connection);
-}
-
-static void
-data_cal_factory_bus_name_lost (EDBusServer *server,
- GDBusConnection *connection)
+data_cal_factory_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
{
- EDataCalFactory *factory;
-
- factory = E_DATA_CAL_FACTORY (server);
-
- data_cal_factory_connections_remove_all (factory);
-
- /* Chain up to parent's bus_name_lost() method. */
- E_DBUS_SERVER_CLASS (e_data_cal_factory_parent_class)->
- bus_name_lost (server, connection);
+ /* Chain up to parent interface's init() method. */
+ return initable_parent_interface->init (initable, cancellable, error);
}
static void
-data_cal_factory_quit_server (EDBusServer *server,
- EDBusServerExitCode exit_code)
-{
- /* This factory does not support reloading, so stop the signal
- * emission and return without chaining up to prevent quitting. */
- if (exit_code == E_DBUS_SERVER_EXIT_RELOAD) {
- g_signal_stop_emission_by_name (server, "quit-server");
- return;
- }
-
- /* Chain up to parent's quit_server() method. */
- E_DBUS_SERVER_CLASS (e_data_cal_factory_parent_class)->
- quit_server (server, exit_code);
-}
-
-static gboolean
-data_cal_factory_initable_init (GInitable *initable,
- GCancellable *cancellable,
- GError **error)
+e_data_cal_factory_initable_init (GInitableIface *iface)
{
- EDataCalFactoryPrivate *priv;
-
- priv = E_DATA_CAL_FACTORY_GET_PRIVATE (initable);
-
- priv->registry = e_source_registry_new_sync (cancellable, error);
+ initable_parent_interface = g_type_interface_peek_parent (iface);
- return (priv->registry != NULL);
+ iface->init = data_cal_factory_initable_init;
}
static void
e_data_cal_factory_class_init (EDataCalFactoryClass *class)
{
- GObjectClass *object_class;
EDBusServerClass *dbus_server_class;
EDataFactoryClass *data_factory_class;
const gchar *modules_directory = BACKENDDIR;
@@ -653,39 +155,71 @@ e_data_cal_factory_class_init (EDataCalFactoryClass *class)
g_type_class_add_private (class, sizeof (EDataCalFactoryPrivate));
- object_class = G_OBJECT_CLASS (class);
- object_class->get_property = data_cal_factory_get_property;
- object_class->dispose = data_cal_factory_dispose;
- object_class->finalize = data_cal_factory_finalize;
-
dbus_server_class = E_DBUS_SERVER_CLASS (class);
dbus_server_class->bus_name = CALENDAR_DBUS_SERVICE_NAME;
dbus_server_class->module_directory = modules_directory;
- dbus_server_class->bus_acquired = data_cal_factory_bus_acquired;
- dbus_server_class->bus_name_lost = data_cal_factory_bus_name_lost;
- dbus_server_class->quit_server = data_cal_factory_quit_server;
data_factory_class = E_DATA_FACTORY_CLASS (class);
data_factory_class->backend_factory_type = E_TYPE_CAL_BACKEND_FACTORY;
+ data_factory_class->factory_object_path = "/org/gnome/evolution/dataserver/CalendarFactory";
+ data_factory_class->data_object_path_prefix = "/org/gnome/evolution/dataserver/Calendar";
+ data_factory_class->get_dbus_interface_skeleton = data_cal_factory_get_dbus_interface_skeleton;
+ data_factory_class->data_open = data_cal_factory_open;
+}
- g_object_class_install_property (
- object_class,
- PROP_REGISTRY,
- g_param_spec_object (
- "registry",
- "Registry",
- "Data source registry",
- E_TYPE_SOURCE_REGISTRY,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
+#define HANDLE_OPEN_CB(extension_name, minus) \
+ GDBusConnection *connection; \
+ const gchar *sender; \
+ gchar *object_path; \
+ GError *error = NULL; \
+ \
+ connection = g_dbus_method_invocation_get_connection (invocation); \
+ sender = g_dbus_method_invocation_get_sender (invocation); \
+ \
+ object_path = e_data_factory_open_backend ( \
+ E_DATA_FACTORY (factory), connection, sender, \
+ uid, extension_name, &error); \
+ \
+ if (object_path != NULL) { \
+ e_dbus_calendar_factory_complete_open_##minus ( \
+ dbus_interface, invocation, object_path); \
+ g_free (object_path); \
+ } else { \
+ g_return_val_if_fail (error != NULL, FALSE); \
+ g_dbus_method_invocation_take_error (invocation, error); \
+ } \
+ \
+ return TRUE;
+
+static gboolean
+data_cal_factory_handle_open_calendar_cb (EDBusCalendarFactory *dbus_interface,
+ GDBusMethodInvocation *invocation,
+ const gchar *uid,
+ EDataCalFactory *factory)
+{
+ HANDLE_OPEN_CB (E_SOURCE_EXTENSION_CALENDAR, calendar);
}
-static void
-e_data_cal_factory_initable_init (GInitableIface *iface)
+static gboolean
+data_cal_factory_handle_open_task_list_cb (EDBusCalendarFactory *dbus_interface,
+ GDBusMethodInvocation *invocation,
+ const gchar *uid,
+ EDataCalFactory *factory)
{
- iface->init = data_cal_factory_initable_init;
+ HANDLE_OPEN_CB (E_SOURCE_EXTENSION_TASK_LIST, task_list);
}
+static gboolean
+data_cal_factory_handle_open_memo_list_cb (EDBusCalendarFactory *dbus_interface,
+ GDBusMethodInvocation *invocation,
+ const gchar *uid,
+ EDataCalFactory *factory)
+{
+ HANDLE_OPEN_CB (E_SOURCE_EXTENSION_MEMO_LIST, memo_list);
+}
+
+
+
static void
e_data_cal_factory_init (EDataCalFactory *factory)
{
@@ -708,21 +242,6 @@ e_data_cal_factory_init (EDataCalFactory *factory)
factory->priv->dbus_factory, "handle-open-memo-list",
G_CALLBACK (data_cal_factory_handle_open_memo_list_cb),
factory);
-
- factory->priv->connections = g_hash_table_new_full (
- (GHashFunc) g_str_hash,
- (GEqualFunc) g_str_equal,
- (GDestroyNotify) g_free,
- (GDestroyNotify) g_ptr_array_unref);
-
- g_mutex_init (&factory->priv->connections_lock);
- g_mutex_init (&factory->priv->watched_names_lock);
-
- factory->priv->watched_names = g_hash_table_new_full (
- (GHashFunc) g_str_hash,
- (GEqualFunc) g_str_equal,
- (GDestroyNotify) g_free,
- (GDestroyNotify) watched_names_value_free);
}
EDBusServer *
@@ -763,21 +282,3 @@ e_data_cal_factory_new (GCancellable *cancellable,
E_TYPE_DATA_CAL_FACTORY,
cancellable, error, NULL);
}
-
-/**
- * e_data_cal_factory_get_registry:
- * @factory: an #EDataCalFactory
- *
- * Returns the #ESourceRegistry owned by @factory.
- *
- * Returns: the #ESourceRegistry
- *
- * Since: 3.6
- **/
-ESourceRegistry *
-e_data_cal_factory_get_registry (EDataCalFactory *factory)
-{
- g_return_val_if_fail (E_IS_DATA_CAL_FACTORY (factory), NULL);
-
- return factory->priv->registry;
-}
diff --git a/calendar/libedata-cal/e-data-cal-factory.h b/calendar/libedata-cal/e-data-cal-factory.h
index e8fec09..18d16d4 100644
--- a/calendar/libedata-cal/e-data-cal-factory.h
+++ b/calendar/libedata-cal/e-data-cal-factory.h
@@ -72,8 +72,6 @@ struct _EDataCalFactoryClass {
GType e_data_cal_factory_get_type (void);
EDBusServer * e_data_cal_factory_new (GCancellable *cancellable,
GError **error);
-ESourceRegistry *
- e_data_cal_factory_get_registry (EDataCalFactory *factory);
G_END_DECLS
diff --git a/calendar/libedata-cal/e-data-cal.c b/calendar/libedata-cal/e-data-cal.c
index d42516f..22753ff 100644
--- a/calendar/libedata-cal/e-data-cal.c
+++ b/calendar/libedata-cal/e-data-cal.c
@@ -218,6 +218,14 @@ data_cal_convert_to_client_error (GError *error)
{
g_return_if_fail (error != NULL);
+ /* Data-Factory returns common error for unknown/broken ESource-s */
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
+ error->domain = E_CAL_CLIENT_ERROR;
+ error->code = E_CAL_CLIENT_ERROR_NO_SUCH_CALENDAR;
+
+ return;
+ }
+
if (error->domain != E_DATA_CAL_ERROR)
return;
diff --git a/configure.ac b/configure.ac
index 293fb94..9c029b2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -114,11 +114,11 @@ LIBECAL_CURRENT=16
LIBECAL_REVISION=0
LIBECAL_AGE=0
-LIBEDATACAL_CURRENT=23
+LIBEDATACAL_CURRENT=24
LIBEDATACAL_REVISION=0
LIBEDATACAL_AGE=0
-LIBEDATABOOK_CURRENT=20
+LIBEDATABOOK_CURRENT=21
LIBEDATABOOK_REVISION=0
LIBEDATABOOK_AGE=0
@@ -134,7 +134,7 @@ LIBCAMEL_CURRENT=49
LIBCAMEL_REVISION=0
LIBCAMEL_AGE=0
-LIBEBACKEND_CURRENT=7
+LIBEBACKEND_CURRENT=8
LIBEBACKEND_REVISION=0
LIBEBACKEND_AGE=0
diff --git a/docs/reference/eds/eds-sections.txt b/docs/reference/eds/eds-sections.txt
index 30684c9..cd8bd29 100644
--- a/docs/reference/eds/eds-sections.txt
+++ b/docs/reference/eds/eds-sections.txt
@@ -1941,7 +1941,6 @@ EDS_ADDRESS_BOOK_MODULES
EDataBookFactory
EDataBookFactoryClass
e_data_book_factory_new
-e_data_book_factory_get_registry
<SUBSECTION Standard>
EDataBookFactoryPrivate
E_DATA_BOOK_FACTORY
@@ -2032,7 +2031,6 @@ EDS_CALENDAR_MODULES
EDataCalFactory
EDataCalFactoryClass
e_data_cal_factory_new
-e_data_cal_factory_get_registry
<SUBSECTION Standard>
EDataCalFactoryPrivate
E_DATA_CAL_FACTORY
@@ -2089,6 +2087,10 @@ EDataFactoryClass
e_data_factory_ref_backend
e_data_factory_ref_initable_backend
e_data_factory_ref_backend_factory
+e_data_factory_get_registry
+e_data_factory_open
+e_data_factory_construct_path
+e_data_factory_set_backend_callbacks
<SUBSECTION Standard>
EDataFactoryPrivate
E_DATA_FACTORY
diff --git a/libebackend/e-data-factory.c b/libebackend/e-data-factory.c
index 338f9be..a881a35 100644
--- a/libebackend/e-data-factory.c
+++ b/libebackend/e-data-factory.c
@@ -28,12 +28,15 @@
#include <libebackend/e-extensible.h>
#include <libebackend/e-backend-factory.h>
+#include <libebackend/e-dbus-server.h>
#define E_DATA_FACTORY_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_DATA_FACTORY, EDataFactoryPrivate))
struct _EDataFactoryPrivate {
+ ESourceRegistry *registry;
+
/* The mutex guards the 'backends' hash table. The
* 'backend_factories' hash table doesn't really need
* guarding since it gets populated during construction
@@ -45,6 +48,16 @@ struct _EDataFactoryPrivate {
/* Hash Key -> EBackendFactory */
GHashTable *backend_factories;
+
+ /* This is a hash table of client bus names to an array of
+ * EBackend references; one for every connection opened. */
+ GHashTable *connections;
+ GMutex connections_lock;
+
+ /* This is a hash table of client bus names being watched.
+ * The value is the watcher ID for g_bus_unwatch_name(). */
+ GHashTable *watched_names;
+ GMutex watched_names_lock;
};
enum {
@@ -52,10 +65,23 @@ enum {
LAST_SIGNAL
};
+enum {
+ PROP_0,
+ PROP_REGISTRY
+};
+
static guint signals[LAST_SIGNAL];
-G_DEFINE_ABSTRACT_TYPE (
- EDataFactory, e_data_factory, E_TYPE_DBUS_SERVER)
+/* Forward Declarations */
+static void e_data_factory_initable_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (
+ EDataFactory,
+ e_data_factory,
+ E_TYPE_DBUS_SERVER,
+ G_IMPLEMENT_INTERFACE (
+ G_TYPE_INITABLE,
+ e_data_factory_initable_init))
static GWeakRef *
data_factory_backends_lookup (EDataFactory *data_factory,
@@ -76,15 +102,276 @@ data_factory_backends_lookup (EDataFactory *data_factory,
}
static void
+watched_names_value_free (gpointer value)
+{
+ g_bus_unwatch_name (GPOINTER_TO_UINT (value));
+}
+
+static void
+data_factory_bus_acquired (EDBusServer *server,
+ GDBusConnection *connection)
+{
+ GDBusInterfaceSkeleton *skeleton_interface;
+ EDataFactoryClass *class;
+ GError *error = NULL;
+
+ class = E_DATA_FACTORY_GET_CLASS (E_DATA_FACTORY (server));
+
+ skeleton_interface = class->get_dbus_interface_skeleton (server);
+
+ g_dbus_interface_skeleton_export (
+ skeleton_interface,
+ connection,
+ class->factory_object_path,
+ &error);
+
+ if (error != NULL) {
+ g_warning ("%s: %s", G_STRFUNC, error->message);
+ e_dbus_server_quit (server, E_DBUS_SERVER_EXIT_NORMAL);
+ g_error_free (error);
+
+ return;
+ }
+
+ /* Chain up to parent's bus_acquired() method. */
+ E_DBUS_SERVER_CLASS (e_data_factory_parent_class)->
+ bus_acquired (server, connection);
+}
+
+static void
+data_factory_connections_add (EDataFactory *data_factory,
+ const gchar *name,
+ EBackend *backend)
+{
+ GHashTable *connections;
+ GPtrArray *array;
+
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (backend != NULL);
+
+ g_mutex_lock (&data_factory->priv->connections_lock);
+
+ connections = data_factory->priv->connections;
+
+ if (g_hash_table_size (connections) == 0)
+ e_dbus_server_hold (E_DBUS_SERVER (data_factory));
+
+ array = g_hash_table_lookup (connections, name);
+
+ if (array == NULL) {
+ array = g_ptr_array_new_with_free_func (
+ (GDestroyNotify) g_object_unref);
+ g_hash_table_insert (
+ connections, g_strdup (name), array);
+ }
+
+ g_ptr_array_add (array, g_object_ref (backend));
+
+ g_mutex_unlock (&data_factory->priv->connections_lock);
+}
+
+static gboolean
+data_factory_connections_remove (EDataFactory *data_factory,
+ const gchar *name,
+ EBackend *backend)
+{
+ GHashTable *connections;
+ GPtrArray *array;
+ gboolean removed = FALSE;
+
+ /* If backend is NULL, we remove all backends for name. */
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ g_mutex_lock (&data_factory->priv->connections_lock);
+
+ connections = data_factory->priv->connections;
+ array = g_hash_table_lookup (connections, name);
+
+ if (array != NULL) {
+ if (backend != NULL) {
+ removed = g_ptr_array_remove_fast (array, backend);
+ } else if (array->len > 0) {
+ g_ptr_array_set_size (array, 0);
+ removed = TRUE;
+ }
+
+ if (array->len == 0)
+ g_hash_table_remove (connections, name);
+
+ if (g_hash_table_size (connections) == 0)
+ e_dbus_server_release (E_DBUS_SERVER (data_factory));
+ }
+
+ g_mutex_unlock (&data_factory->priv->connections_lock);
+
+ return removed;
+}
+
+static void
+data_factory_connections_remove_all (EDataFactory *data_factory)
+{
+ GHashTable *connections;
+
+ g_mutex_lock (&data_factory->priv->connections_lock);
+
+ connections = data_factory->priv->connections;
+
+ if (g_hash_table_size (connections) > 0) {
+ g_hash_table_remove_all (connections);
+ e_dbus_server_release (E_DBUS_SERVER (data_factory));
+ }
+
+ g_mutex_unlock (&data_factory->priv->connections_lock);
+}
+
+static void
+data_factory_closed_cb (EBackend *backend,
+ const gchar *sender,
+ EDataFactory *data_factory)
+{
+ data_factory_connections_remove (data_factory, sender, backend);
+}
+
+static void
+data_factory_name_vanished_cb (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ GWeakRef *weak_ref = user_data;
+ EDataFactory *data_factory;
+
+ data_factory = g_weak_ref_get (weak_ref);
+
+ if (data_factory != NULL) {
+ data_factory_connections_remove (data_factory, name, NULL);
+
+ /* Unwatching the bus name from here will corrupt the
+ * 'name' argument, and possibly also the 'user_data'.
+ *
+ * This is a GDBus bug. Work around it by unwatching
+ * the bus name last.
+ *
+ * See: https://bugzilla.gnome.org/706088
+ */
+ g_mutex_lock (&data_factory->priv->watched_names_lock);
+ g_hash_table_remove (data_factory->priv->watched_names, name);
+ g_mutex_unlock (&data_factory->priv->watched_names_lock);
+
+ g_object_unref (data_factory);
+ }
+}
+
+static void
+data_factory_watched_names_add (EDataFactory *data_factory,
+ GDBusConnection *connection,
+ const gchar *name)
+{
+ GHashTable *watched_names;
+
+ g_return_if_fail (name != NULL);
+
+ g_mutex_lock (&data_factory->priv->watched_names_lock);
+
+ watched_names = data_factory->priv->watched_names;
+
+ if (!g_hash_table_contains (watched_names, name)) {
+ guint watcher_id;
+
+ /* The g_bus_watch_name() documentation says one of the two
+ * callbacks are guaranteed to be invoked after calling the
+ * function. But which one is determined asynchronously so
+ * there should be no chance of the name vanished callback
+ * deadlocking with us when it tries to acquire the lock. */
+ watcher_id = g_bus_watch_name_on_connection (
+ connection, name,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ (GBusNameAppearedCallback) NULL,
+ data_factory_name_vanished_cb,
+ e_weak_ref_new (data_factory),
+ (GDestroyNotify) e_weak_ref_free);
+
+ g_hash_table_insert (
+ watched_names, g_strdup (name),
+ GUINT_TO_POINTER (watcher_id));
+ }
+
+ g_mutex_unlock (&data_factory->priv->watched_names_lock);
+}
+
+static void
+data_factory_bus_name_lost (EDBusServer *server,
+ GDBusConnection *connection)
+{
+ EDataFactory *data_factory;
+
+ data_factory = E_DATA_FACTORY (server);
+
+ data_factory_connections_remove_all (data_factory);
+
+ /* Chain up to parent's bus_name_lost() method. */
+ E_DBUS_SERVER_CLASS (e_data_factory_parent_class)->
+ bus_name_lost (server, connection);
+}
+
+static void
+data_factory_quit_server (EDBusServer *server,
+ EDBusServerExitCode exit_code)
+{
+ GDBusInterfaceSkeleton *skeleton_interface;
+ EDataFactoryClass *class;
+
+ class = E_DATA_FACTORY_GET_CLASS (E_DATA_FACTORY (server));
+
+ skeleton_interface = class->get_dbus_interface_skeleton (server);
+ g_dbus_interface_skeleton_unexport (skeleton_interface);
+
+ /* This factory does not support reloading, so stop the signal
+ * emission and return without chaining up to prevent quitting. */
+ if (exit_code == E_DBUS_SERVER_EXIT_RELOAD) {
+ g_signal_stop_emission_by_name (server, "quit-server");
+ return;
+ }
+
+ /* Chain up to parent's quit_server() method. */
+ E_DBUS_SERVER_CLASS (e_data_factory_parent_class)->
+ quit_server (server, exit_code);
+}
+
+static void
+e_data_factory_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_REGISTRY:
+ g_value_set_object (
+ value,
+ e_data_factory_get_registry (
+ E_DATA_FACTORY (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
data_factory_dispose (GObject *object)
{
+ EDataFactory *data_factory;
EDataFactoryPrivate *priv;
- priv = E_DATA_FACTORY_GET_PRIVATE (object);
+ data_factory = E_DATA_FACTORY (object);
+ priv = data_factory->priv;
g_hash_table_remove_all (priv->backends);
g_hash_table_remove_all (priv->backend_factories);
+ g_clear_object (&priv->registry);
+
+ g_hash_table_remove_all (priv->connections);
+ g_hash_table_remove_all (priv->watched_names);
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_data_factory_parent_class)->dispose (object);
}
@@ -92,15 +379,23 @@ data_factory_dispose (GObject *object)
static void
data_factory_finalize (GObject *object)
{
+ EDataFactory *data_factory;
EDataFactoryPrivate *priv;
- priv = E_DATA_FACTORY_GET_PRIVATE (object);
+ data_factory = E_DATA_FACTORY (object);
+ priv = data_factory->priv;
g_mutex_clear (&priv->mutex);
g_hash_table_destroy (priv->backends);
g_hash_table_destroy (priv->backend_factories);
+ g_hash_table_destroy (priv->connections);
+ g_mutex_clear (&priv->connections_lock);
+
+ g_hash_table_destroy (priv->watched_names);
+ g_mutex_clear (&priv->watched_names_lock);
+
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_data_factory_parent_class)->finalize (object);
}
@@ -109,11 +404,11 @@ static void
data_factory_constructed (GObject *object)
{
EDataFactoryClass *class;
- EDataFactoryPrivate *priv;
+ EDataFactory *data_factory;
GList *list, *link;
- class = E_DATA_FACTORY_GET_CLASS (object);
- priv = E_DATA_FACTORY_GET_PRIVATE (object);
+ data_factory = E_DATA_FACTORY (object);
+ class = E_DATA_FACTORY_GET_CLASS (data_factory);
/* Chain up to parent's constructed() method. */
G_OBJECT_CLASS (e_data_factory_parent_class)->constructed (object);
@@ -132,7 +427,7 @@ data_factory_constructed (GObject *object)
if (hash_key != NULL) {
g_hash_table_insert (
- priv->backend_factories,
+ data_factory->priv->backend_factories,
g_strdup (hash_key),
g_object_ref (backend_factory));
g_debug (
@@ -145,20 +440,59 @@ data_factory_constructed (GObject *object)
g_list_free (list);
}
+static gboolean
+data_factory_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EDataFactory *data_factory;
+
+ data_factory = E_DATA_FACTORY (initable);
+
+ data_factory->priv->registry = e_source_registry_new_sync (
+ cancellable, error);
+
+ return (data_factory->priv->registry != NULL);
+}
+
+static void
+e_data_factory_initable_init (GInitableIface *iface)
+{
+ iface->init = data_factory_initable_init;
+}
+
static void
e_data_factory_class_init (EDataFactoryClass *class)
{
GObjectClass *object_class;
+ EDBusServerClass *dbus_server_class;
g_type_class_add_private (class, sizeof (EDataFactoryPrivate));
object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = e_data_factory_get_property;
object_class->dispose = data_factory_dispose;
object_class->finalize = data_factory_finalize;
object_class->constructed = data_factory_constructed;
class->backend_factory_type = E_TYPE_BACKEND_FACTORY;
+ dbus_server_class = E_DBUS_SERVER_CLASS (class);
+ dbus_server_class->bus_acquired = data_factory_bus_acquired;
+ dbus_server_class->bus_name_lost = data_factory_bus_name_lost;
+ dbus_server_class->quit_server = data_factory_quit_server;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_REGISTRY,
+ g_param_spec_object (
+ "registry",
+ "Registry",
+ "Data source registry",
+ E_TYPE_SOURCE_REGISTRY,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
/**
* EDataFactory::backend-created:
* @data_factory: the #EDataFactory which emitted the signal
@@ -186,6 +520,8 @@ e_data_factory_init (EDataFactory *data_factory)
data_factory->priv = E_DATA_FACTORY_GET_PRIVATE (data_factory);
g_mutex_init (&data_factory->priv->mutex);
+ g_mutex_init (&data_factory->priv->connections_lock);
+ g_mutex_init (&data_factory->priv->watched_names_lock);
data_factory->priv->backends = g_hash_table_new_full (
(GHashFunc) g_str_hash,
@@ -198,6 +534,18 @@ e_data_factory_init (EDataFactory *data_factory)
(GEqualFunc) g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) g_object_unref);
+
+ data_factory->priv->connections = g_hash_table_new_full (
+ (GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_ptr_array_unref);
+
+ data_factory->priv->watched_names = g_hash_table_new_full (
+ (GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) watched_names_value_free);
}
/**
@@ -205,6 +553,7 @@ e_data_factory_init (EDataFactory *data_factory)
* @data_factory: an #EDataFactory
* @hash_key: hash key for an #EBackendFactory
* @source: an #ESource
+ * @error: return location for a #GError, or %NULL
*
* Returns either a newly-created or existing #EBackend for #ESource.
* The returned #EBackend is referenced for thread-safety and must be
@@ -374,3 +723,266 @@ e_data_factory_ref_backend_factory (EDataFactory *data_factory,
return backend_factory;
}
+static void
+data_factory_toggle_notify_cb (gpointer data,
+ GObject *backend,
+ gboolean is_last_ref)
+{
+ if (is_last_ref) {
+ /* Take a strong reference before removing the
+ * toggle reference, to keep the backend alive. */
+ g_object_ref (backend);
+
+ g_object_remove_toggle_ref (
+ backend, data_factory_toggle_notify_cb, data);
+
+ g_signal_emit_by_name (backend, "shutdown");
+
+ g_object_unref (backend);
+ }
+}
+
+/**
+ * e_data_factory_get_registry:
+ * @data_factory: an #EDataFactory
+ * @backend: an #EBackend
+ *
+ * Install a toggle reference on the backend, that can receive a signal to
+ * shutdown once all client connections are closed.
+ *
+ * Since: 3.14
+ **/
+void
+e_data_factory_set_backend_callbacks (EDataFactory *data_factory,
+ EBackend *backend)
+{
+ g_return_if_fail (E_IS_DATA_FACTORY (data_factory));
+ g_return_if_fail (data_factory != NULL);
+ g_return_if_fail (backend != NULL);
+
+ /* Install a toggle reference on the backend
+ * so we can signal it to shut down once all
+ * client connections are closed.
+ */
+ g_object_add_toggle_ref (
+ G_OBJECT (backend),
+ data_factory_toggle_notify_cb,
+ NULL);
+
+ g_signal_connect_object (
+ backend, "closed",
+ G_CALLBACK (data_factory_closed_cb),
+ data_factory, 0);
+}
+
+/**
+ * e_data_factory_get_registry:
+ * @data_factory: an #EDataFactory
+ *
+ * Returns the #ESourceRegistry owned by @data_factory.
+ *
+ * Returns: the #ESourceRegistry
+ *
+ * Since: 3.14
+ **/
+ESourceRegistry *
+e_data_factory_get_registry (EDataFactory *data_factory)
+{
+ g_return_val_if_fail (E_IS_DATA_FACTORY (data_factory), NULL);
+
+ return data_factory->priv->registry;
+}
+
+/**
+ * e_data_factory_list_backends:
+ * @data_factory: an #EDataFactory
+ *
+ * Returns a list of backends connected to the @data_factory
+ *
+ * Returns: a #GSList of backends connected to the @data_factory.
+ * The list should be freed using
+ * g_slist_free_full (backends, g_object_unref)
+ *
+ * Since: 3.14
+ **/
+GSList *
+e_data_factory_list_backends (EDataFactory *data_factory)
+{
+ GSList *backends = NULL;
+ GHashTable *connections;
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_return_val_if_fail (E_IS_DATA_FACTORY (data_factory), NULL);
+
+ g_mutex_lock (&data_factory->priv->connections_lock);
+
+ connections = data_factory->priv->connections;
+
+ g_hash_table_iter_init (&iter, connections);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ GPtrArray *array = value;
+ gint ii;
+
+ for (ii = 0; ii < array->len; ii++) {
+ EBackend *backend = g_ptr_array_index (array, ii);
+ backends = g_slist_prepend (backends, g_object_ref (backend));
+ }
+ }
+
+ backends = g_slist_reverse (backends);
+ g_mutex_unlock (&data_factory->priv->connections_lock);
+
+ return backends;
+}
+
+static EBackend *
+data_factory_ref_backend (EDataFactory *data_factory,
+ ESource *source,
+ const gchar *extension_name,
+ GError **error)
+{
+ EBackend *backend;
+ ESourceBackend *extension;
+ gchar *backend_name;
+ gchar *hash_key = NULL;
+
+ g_return_val_if_fail (E_IS_DATA_FACTORY (data_factory), NULL);
+
+ extension = e_source_get_extension (source, extension_name);
+ backend_name = e_source_backend_dup_backend_name (extension);
+
+ if (backend_name == NULL || *backend_name == '\0') {
+ g_set_error (
+ error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("No backend name in source '%s'"),
+ e_source_get_display_name (source));
+ g_free (backend_name);
+ return NULL;
+ }
+
+ hash_key = g_strdup_printf ("%s:%s", backend_name, extension_name);
+
+ backend = e_data_factory_ref_initable_backend (
+ data_factory,
+ hash_key,
+ source,
+ NULL,
+ error);
+
+ g_free (hash_key);
+ g_free (backend_name);
+
+ return backend;
+}
+
+/**
+ * e_data_factory_construct_path:
+ * @data_factory: an #EDataFactory
+ *
+ * Returns a new and unique object path for a D-Bus interface based
+ * in the data object path prefix of the @data_factory
+ *
+ * Returns: a newly allocated string, representing the object path for
+ * the D-Bus interface.
+ *
+ * Since: 3.14
+ **/
+gchar *
+e_data_factory_construct_path (EDataFactory *data_factory)
+{
+ EDataFactoryClass *class;
+ static volatile gint counter = 1;
+
+ g_return_val_if_fail (E_IS_DATA_FACTORY (data_factory), NULL);
+
+ g_atomic_int_inc (&counter);
+
+ class = E_DATA_FACTORY_GET_CLASS (data_factory);
+ g_return_val_if_fail (class->data_object_path_prefix != NULL, NULL);
+
+ return g_strdup_printf (
+ "%s/%d/%u",
+ class->data_object_path_prefix, getpid (), counter);
+}
+
+/**
+ * e_data_factory_open_backend:
+ * @data_factory: an #EDataFactory
+ * @connection: a #GDBusConnection
+ * @sender: a string
+ * @uid: UID of an #ESource to open
+ * @extension_name: an extension name
+ * @error: return location for a #GError, or %NULL
+ *
+ * Returns the #EBackend data D-Bus object path
+ *
+ * Returns: a newly allocated string that represents the #EBackend
+ * data D-Bus object path.
+ *
+ * Since: 3.14
+ **/
+gchar *
+e_data_factory_open_backend (EDataFactory *data_factory,
+ GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *uid,
+ const gchar *extension_name,
+ GError **error)
+{
+ EDataFactoryClass *class;
+ EBackend *backend;
+ ESourceRegistry *registry;
+ ESource *source;
+ gchar *object_path;
+
+ g_return_val_if_fail (E_IS_DATA_FACTORY (data_factory), NULL);
+
+ if (uid == NULL || *uid == '\0') {
+ g_set_error (
+ error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("Missing source UID"));
+ return NULL;
+ }
+
+ registry = e_data_factory_get_registry (data_factory);
+ source = e_source_registry_ref_source (registry, uid);
+
+ if (source == NULL) {
+ g_set_error (
+ error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ _("No such source for UID '%s'"), uid);
+ return NULL;
+ }
+
+ backend = data_factory_ref_backend (
+ data_factory, source, extension_name, error);
+
+ g_object_unref (source);
+
+ if (backend == NULL)
+ return NULL;
+
+ class = E_DATA_FACTORY_GET_CLASS (data_factory);
+ object_path = class->data_open (
+ data_factory, backend, connection, error);
+
+ if (object_path != NULL) {
+ /* Watch the sender's bus name so we can clean
+ * up its connections if the bus name vanishes.
+ */
+ data_factory_watched_names_add (
+ data_factory, connection, sender);
+
+ /* A client my create multiple Eclient instances for the
+ * same ESource, each of which calls close() individually.
+ * So we must track each and every connection made.
+ */
+ data_factory_connections_add (
+ data_factory, sender, backend);
+ }
+
+ g_clear_object (&backend);
+
+ return object_path;
+}
diff --git a/libebackend/e-data-factory.h b/libebackend/e-data-factory.h
index 88d0213..676be07 100644
--- a/libebackend/e-data-factory.h
+++ b/libebackend/e-data-factory.h
@@ -68,10 +68,23 @@ struct _EDataFactoryClass {
GType backend_factory_type;
+ const gchar *factory_object_path;
+ const gchar *data_object_path_prefix;
+
/* Signals */
void (*backend_created) (EDataFactory *data_factory,
EBackend *backend);
+ /* Virtual methods */
+ GDBusInterfaceSkeleton *
+ (*get_dbus_interface_skeleton)
+ (EDBusServer *server);
+
+ gchar * (*data_open) (EDataFactory *data_factory,
+ EBackend *backend,
+ GDBusConnection *connection,
+ GError **error);
+
gpointer reserved[15];
};
@@ -89,6 +102,19 @@ EBackendFactory *
e_data_factory_ref_backend_factory
(EDataFactory *data_factory,
const gchar *hash_key);
+ESourceRegistry *
+ e_data_factory_get_registry (EDataFactory *data_factory);
+GSList * e_data_factory_list_backends (EDataFactory *data_factory);
+gchar * e_data_factory_open_backend (EDataFactory *data_factory,
+ GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *uid,
+ const gchar *extension_name,
+ GError **error);
+gchar * e_data_factory_construct_path (EDataFactory *data_factory);
+void e_data_factory_set_backend_callbacks
+ (EDataFactory *data_factory,
+ EBackend *backend);
G_END_DECLS
diff --git a/libebackend/e-source-registry-server.c b/libebackend/e-source-registry-server.c
index 7525b8b..6ab0c9d 100644
--- a/libebackend/e-source-registry-server.c
+++ b/libebackend/e-source-registry-server.c
@@ -85,8 +85,6 @@ struct _ESourceRegistryServerPrivate {
GMutex auth_lock;
GHashTable *running_auths;
GHashTable *waiting_auths;
-
- guint authentication_count;
};
struct _AuthRequest {
@@ -684,7 +682,6 @@ source_registry_server_authenticate_cb (EDBusSourceManager *dbus_interface,
GDBusConnection *connection;
EAuthenticationSession *session;
ESourceAuthenticator *authenticator;
- const gchar *base_object_path;
const gchar *sender;
gchar *auth_object_path;
GError *error = NULL;
@@ -693,13 +690,11 @@ source_registry_server_authenticate_cb (EDBusSourceManager *dbus_interface,
* effectively starts a new authentication session with the
* method caller. */
- base_object_path = E_SOURCE_REGISTRY_SERVER_OBJECT_PATH;
connection = g_dbus_method_invocation_get_connection (invocation);
sender = g_dbus_method_invocation_get_sender (invocation);
- auth_object_path = g_strdup_printf (
- "%s/auth_%u", base_object_path,
- server->priv->authentication_count++);
+ auth_object_path = e_data_factory_construct_path (
+ E_DATA_FACTORY (server));
authenticator = e_authentication_mediator_new (
connection, auth_object_path, sender, &error);
@@ -1102,24 +1097,12 @@ source_registry_server_bus_acquired (EDBusServer *server,
GDBusConnection *connection)
{
ESourceRegistryServerPrivate *priv;
- GError *error = NULL;
priv = E_SOURCE_REGISTRY_SERVER_GET_PRIVATE (server);
g_dbus_object_manager_server_set_connection (
priv->object_manager, connection);
- g_dbus_interface_skeleton_export (
- G_DBUS_INTERFACE_SKELETON (priv->source_manager),
- connection, E_SOURCE_REGISTRY_SERVER_OBJECT_PATH, &error);
-
- /* Terminate the server if we can't export the interface. */
- if (error != NULL) {
- g_warning ("%s: %s", G_STRFUNC, error->message);
- e_dbus_server_quit (server, E_DBUS_SERVER_EXIT_NORMAL);
- g_error_free (error);
- }
-
/* Chain up to parent's bus_acquired() method. */
E_DBUS_SERVER_CLASS (e_source_registry_server_parent_class)->
bus_acquired (server, connection);
@@ -1140,9 +1123,6 @@ source_registry_server_quit_server (EDBusServer *server,
g_dbus_object_manager_server_set_connection (
priv->object_manager, NULL);
- g_dbus_interface_skeleton_unexport (
- G_DBUS_INTERFACE_SKELETON (priv->source_manager));
-
/* Chain up to parent's quit_server() method. */
E_DBUS_SERVER_CLASS (e_source_registry_server_parent_class)->
quit_server (server, code);
@@ -1250,6 +1230,16 @@ source_registry_server_any_true (GSignalInvocationHint *ihint,
return TRUE;
}
+static GDBusInterfaceSkeleton *
+source_registry_server_get_dbus_interface_skeleton (EDBusServer *server)
+{
+ ESourceRegistryServerPrivate *priv;
+
+ priv = E_SOURCE_REGISTRY_SERVER_GET_PRIVATE (server);
+
+ return G_DBUS_INTERFACE_SKELETON (priv->source_manager);
+}
+
static void
e_source_registry_server_class_init (ESourceRegistryServerClass *class)
{
@@ -1276,10 +1266,12 @@ e_source_registry_server_class_init (ESourceRegistryServerClass *class)
dbus_server_class->module_directory = modules_directory;
dbus_server_class->bus_acquired = source_registry_server_bus_acquired;
dbus_server_class->quit_server = source_registry_server_quit_server;
-
data_factory_class = E_DATA_FACTORY_CLASS (class);
backend_factory_type = E_TYPE_COLLECTION_BACKEND_FACTORY;
data_factory_class->backend_factory_type = backend_factory_type;
+ data_factory_class->factory_object_path = E_SOURCE_REGISTRY_SERVER_OBJECT_PATH;
+ data_factory_class->data_object_path_prefix = E_SOURCE_REGISTRY_SERVER_OBJECT_PATH;
+ data_factory_class->get_dbus_interface_skeleton = source_registry_server_get_dbus_interface_skeleton;
class->source_added = source_registry_server_source_added;
class->source_removed = source_registry_server_source_removed;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]