4 * This library is free software you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, see <http://www.gnu.org/licenses/>.
19 * SECTION: e-data-factory
20 * @include: libebackend/libebackend.h
21 * @short_description: An abstract base class for a backend-based server
24 #include "e-data-factory.h"
27 #include <glib/gi18n-lib.h>
29 #include <libebackend/e-extensible.h>
30 #include <libebackend/e-backend-factory.h>
32 #define E_DATA_FACTORY_GET_PRIVATE(obj) \
33 (G_TYPE_INSTANCE_GET_PRIVATE \
34 ((obj), E_TYPE_DATA_FACTORY, EDataFactoryPrivate))
36 struct _EDataFactoryPrivate {
37 /* The mutex guards the 'backends' hash table. The
38 * 'backend_factories' hash table doesn't really need
39 * guarding since it gets populated during construction
40 * and is read-only thereafter. */
43 /* ESource UID -> GWeakRef (EBackend) */
46 /* Hash Key -> EBackendFactory */
47 GHashTable *backend_factories;
55 static guint signals[LAST_SIGNAL];
57 G_DEFINE_ABSTRACT_TYPE (
58 EDataFactory, e_data_factory, E_TYPE_DBUS_SERVER)
61 data_factory_backends_lookup (EDataFactory *data_factory,
67 backends = data_factory->priv->backends;
68 weak_ref = g_hash_table_lookup (backends, uid);
70 if (weak_ref == NULL) {
71 weak_ref = e_weak_ref_new (NULL);
72 g_hash_table_insert (backends, g_strdup (uid), weak_ref);
79 data_factory_dispose (GObject *object)
81 EDataFactoryPrivate *priv;
83 priv = E_DATA_FACTORY_GET_PRIVATE (object);
85 g_hash_table_remove_all (priv->backends);
86 g_hash_table_remove_all (priv->backend_factories);
88 /* Chain up to parent's dispose() method. */
89 G_OBJECT_CLASS (e_data_factory_parent_class)->dispose (object);
93 data_factory_finalize (GObject *object)
95 EDataFactoryPrivate *priv;
97 priv = E_DATA_FACTORY_GET_PRIVATE (object);
99 g_mutex_clear (&priv->mutex);
101 g_hash_table_destroy (priv->backends);
102 g_hash_table_destroy (priv->backend_factories);
104 /* Chain up to parent's finalize() method. */
105 G_OBJECT_CLASS (e_data_factory_parent_class)->finalize (object);
109 data_factory_constructed (GObject *object)
111 EDataFactoryClass *class;
112 EDataFactoryPrivate *priv;
115 class = E_DATA_FACTORY_GET_CLASS (object);
116 priv = E_DATA_FACTORY_GET_PRIVATE (object);
118 /* Chain up to parent's constructed() method. */
119 G_OBJECT_CLASS (e_data_factory_parent_class)->constructed (object);
121 /* Collect all backend factories into a hash table. */
123 list = e_extensible_list_extensions (
124 E_EXTENSIBLE (object), class->backend_factory_type);
126 for (link = list; link != NULL; link = g_list_next (link)) {
127 EBackendFactory *backend_factory;
128 const gchar *hash_key;
130 backend_factory = E_BACKEND_FACTORY (link->data);
131 hash_key = e_backend_factory_get_hash_key (backend_factory);
133 if (hash_key != NULL) {
134 g_hash_table_insert (
135 priv->backend_factories,
137 g_object_ref (backend_factory));
139 "Registering %s ('%s')\n",
140 G_OBJECT_TYPE_NAME (backend_factory),
149 e_data_factory_class_init (EDataFactoryClass *class)
151 GObjectClass *object_class;
153 g_type_class_add_private (class, sizeof (EDataFactoryPrivate));
155 object_class = G_OBJECT_CLASS (class);
156 object_class->dispose = data_factory_dispose;
157 object_class->finalize = data_factory_finalize;
158 object_class->constructed = data_factory_constructed;
160 class->backend_factory_type = E_TYPE_BACKEND_FACTORY;
163 * EDataFactory::backend-created:
164 * @data_factory: the #EDataFactory which emitted the signal
165 * @backend: the newly-created #EBackend
167 * Emitted when a new #EBackend is instantiated by way of
168 * e_data_factory_ref_backend(). Extensions can connect to this
169 * signal to perform additional initialization on the #EBackend.
173 signals[BACKEND_CREATED] = g_signal_new (
175 G_OBJECT_CLASS_TYPE (object_class),
177 G_STRUCT_OFFSET (EDataFactoryClass, backend_created),
184 e_data_factory_init (EDataFactory *data_factory)
186 data_factory->priv = E_DATA_FACTORY_GET_PRIVATE (data_factory);
188 g_mutex_init (&data_factory->priv->mutex);
190 data_factory->priv->backends = g_hash_table_new_full (
191 (GHashFunc) g_str_hash,
192 (GEqualFunc) g_str_equal,
193 (GDestroyNotify) g_free,
194 (GDestroyNotify) e_weak_ref_free);
196 data_factory->priv->backend_factories = g_hash_table_new_full (
197 (GHashFunc) g_str_hash,
198 (GEqualFunc) g_str_equal,
199 (GDestroyNotify) g_free,
200 (GDestroyNotify) g_object_unref);
204 * e_data_factory_ref_backend:
205 * @data_factory: an #EDataFactory
206 * @hash_key: hash key for an #EBackendFactory
207 * @source: an #ESource
209 * Returns either a newly-created or existing #EBackend for #ESource.
210 * The returned #EBackend is referenced for thread-safety and must be
211 * unreferenced with g_object_unref() when finished with it.
213 * The @data_factory retains a weak reference to @backend so it can return
214 * the same instance while @backend is in use. When the last strong reference
215 * to @backend is dropped, @data_factory will lose its weak reference and will
216 * have to create a new #EBackend instance the next time the same @hash_key
217 * and @source are requested.
219 * If no suitable #EBackendFactory exists, the function returns %NULL.
221 * Returns: an #EBackend for @source, or %NULL
226 e_data_factory_ref_backend (EDataFactory *data_factory,
227 const gchar *hash_key,
230 return e_data_factory_ref_initable_backend (
231 data_factory, hash_key, source, NULL, NULL);
235 * e_data_factory_ref_initable_backend:
236 * @data_factory: an #EDataFactory
237 * @hash_key: hash key for an #EBackendFactory
238 * @source: an #ESource
239 * @cancellable: optional #GCancellable object, or %NULL
240 * @error: return location for a #GError, or %NULL
242 * Similar to e_data_factory_ref_backend(), but allows for backends that
243 * implement the #GInitable interface so they can fail gracefully if they
244 * are unable to initialize critical resources, such as a cache database.
246 * Returns either a newly-created or existing #EBackend for #ESource.
247 * The returned #EBackend is referenced for thread-safety and must be
248 * unreferenced with g_object_unref() when finished with it.
250 * If the newly-created backend implements the #GInitable interface, then
251 * g_initable_init() is also called on it using @cancellable and @error.
253 * The @data_factory retains a weak reference to @backend so it can return
254 * the same instance while @backend is in use. When the last strong reference
255 * to @backend is dropped, @data_factory will lose its weak reference and will
256 * have to create a new #EBackend instance the next time the same @hash_key
257 * and @source are requested.
259 * If no suitable #EBackendFactory exists, or if the #EBackend fails to
260 * initialize, the function sets @error and returns %NULL.
262 * Returns: an #EBackend for @source, or %NULL
267 e_data_factory_ref_initable_backend (EDataFactory *data_factory,
268 const gchar *hash_key,
270 GCancellable *cancellable,
273 EBackendFactory *backend_factory;
278 g_return_val_if_fail (E_IS_DATA_FACTORY (data_factory), NULL);
279 g_return_val_if_fail (hash_key != NULL, NULL);
280 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
282 uid = e_source_get_uid (source);
283 g_return_val_if_fail (uid != NULL, NULL);
285 g_mutex_lock (&data_factory->priv->mutex);
287 /* The weak ref is already inserted in the hash table. */
288 weak_ref = data_factory_backends_lookup (data_factory, uid);
290 /* Check if we already have a backend for the given source. */
291 backend = g_weak_ref_get (weak_ref);
296 /* Find a suitable backend factory using the hash key. */
298 e_data_factory_ref_backend_factory (data_factory, hash_key);
300 if (backend_factory == NULL) {
302 error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
303 _("No backend factory for hash key '%s'"),
308 /* Create a new backend for the given source and store it. */
309 backend = e_backend_factory_new_backend (backend_factory, source);
311 if (G_IS_INITABLE (backend)) {
312 GInitable *initable = G_INITABLE (backend);
314 if (!g_initable_init (initable, cancellable, error)) {
315 g_object_unref (backend);
320 /* This still does the right thing if backend is NULL. */
321 g_weak_ref_set (weak_ref, backend);
323 g_object_unref (backend_factory);
327 data_factory, signals[BACKEND_CREATED], 0, backend);
330 g_mutex_unlock (&data_factory->priv->mutex);
336 * e_data_factory_ref_backend_factory:
337 * @data_factory: an #EDataFactory
338 * @hash_key: hash key for an #EBackendFactory
340 * Returns the #EBackendFactory for @hash_key, or %NULL if no such factory
343 * The returned #EBackendFactory is referenced for thread-safety.
344 * Unreference the #EBackendFactory with g_object_unref() when finished
347 * Returns: the #EBackendFactory for @hash_key, or %NULL
352 e_data_factory_ref_backend_factory (EDataFactory *data_factory,
353 const gchar *hash_key)
355 GHashTable *backend_factories;
356 EBackendFactory *backend_factory;
358 g_return_val_if_fail (E_IS_DATA_FACTORY (data_factory), NULL);
359 g_return_val_if_fail (hash_key != NULL, NULL);
361 /* It should be safe to lookup backend factories without a mutex
362 * because once initially populated the hash table remains fixed.
364 * XXX Which might imply the returned factory doesn't *really* need
365 * to be referenced for thread-safety, but better to do it when
366 * not really needed than wish we had in the future. */
368 backend_factories = data_factory->priv->backend_factories;
369 backend_factory = g_hash_table_lookup (backend_factories, hash_key);
371 if (backend_factory != NULL)
372 g_object_ref (backend_factory);
374 return backend_factory;