updated changelog
[platform/upstream/evolution-data-server.git] / libebackend / e-data-factory.c
1 /*
2  * e-data-factory.c
3  *
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.
7  *
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
11  * for more details.
12  *
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/>.
15  *
16  */
17
18 /**
19  * SECTION: e-data-factory
20  * @include: libebackend/libebackend.h
21  * @short_description: An abstract base class for a backend-based server
22  **/
23
24 #include "e-data-factory.h"
25
26 #include <config.h>
27 #include <glib/gi18n-lib.h>
28
29 #include <libebackend/e-extensible.h>
30 #include <libebackend/e-backend-factory.h>
31
32 #define E_DATA_FACTORY_GET_PRIVATE(obj) \
33         (G_TYPE_INSTANCE_GET_PRIVATE \
34         ((obj), E_TYPE_DATA_FACTORY, EDataFactoryPrivate))
35
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. */
41         GMutex mutex;
42
43         /* ESource UID -> GWeakRef (EBackend) */
44         GHashTable *backends;
45
46         /* Hash Key -> EBackendFactory */
47         GHashTable *backend_factories;
48 };
49
50 enum {
51         BACKEND_CREATED,
52         LAST_SIGNAL
53 };
54
55 static guint signals[LAST_SIGNAL];
56
57 G_DEFINE_ABSTRACT_TYPE (
58         EDataFactory, e_data_factory, E_TYPE_DBUS_SERVER)
59
60 static GWeakRef *
61 data_factory_backends_lookup (EDataFactory *data_factory,
62                               const gchar *uid)
63 {
64         GHashTable *backends;
65         GWeakRef *weak_ref;
66
67         backends = data_factory->priv->backends;
68         weak_ref = g_hash_table_lookup (backends, uid);
69
70         if (weak_ref == NULL) {
71                 weak_ref = e_weak_ref_new (NULL);
72                 g_hash_table_insert (backends, g_strdup (uid), weak_ref);
73         }
74
75         return weak_ref;
76 }
77
78 static void
79 data_factory_dispose (GObject *object)
80 {
81         EDataFactoryPrivate *priv;
82
83         priv = E_DATA_FACTORY_GET_PRIVATE (object);
84
85         g_hash_table_remove_all (priv->backends);
86         g_hash_table_remove_all (priv->backend_factories);
87
88         /* Chain up to parent's dispose() method. */
89         G_OBJECT_CLASS (e_data_factory_parent_class)->dispose (object);
90 }
91
92 static void
93 data_factory_finalize (GObject *object)
94 {
95         EDataFactoryPrivate *priv;
96
97         priv = E_DATA_FACTORY_GET_PRIVATE (object);
98
99         g_mutex_clear (&priv->mutex);
100
101         g_hash_table_destroy (priv->backends);
102         g_hash_table_destroy (priv->backend_factories);
103
104         /* Chain up to parent's finalize() method. */
105         G_OBJECT_CLASS (e_data_factory_parent_class)->finalize (object);
106 }
107
108 static void
109 data_factory_constructed (GObject *object)
110 {
111         EDataFactoryClass *class;
112         EDataFactoryPrivate *priv;
113         GList *list, *link;
114
115         class = E_DATA_FACTORY_GET_CLASS (object);
116         priv = E_DATA_FACTORY_GET_PRIVATE (object);
117
118         /* Chain up to parent's constructed() method. */
119         G_OBJECT_CLASS (e_data_factory_parent_class)->constructed (object);
120
121         /* Collect all backend factories into a hash table. */
122
123         list = e_extensible_list_extensions (
124                 E_EXTENSIBLE (object), class->backend_factory_type);
125
126         for (link = list; link != NULL; link = g_list_next (link)) {
127                 EBackendFactory *backend_factory;
128                 const gchar *hash_key;
129
130                 backend_factory = E_BACKEND_FACTORY (link->data);
131                 hash_key = e_backend_factory_get_hash_key (backend_factory);
132
133                 if (hash_key != NULL) {
134                         g_hash_table_insert (
135                                 priv->backend_factories,
136                                 g_strdup (hash_key),
137                                 g_object_ref (backend_factory));
138                         g_debug (
139                                 "Registering %s ('%s')\n",
140                                 G_OBJECT_TYPE_NAME (backend_factory),
141                                 hash_key);
142                 }
143         }
144
145         g_list_free (list);
146 }
147
148 static void
149 e_data_factory_class_init (EDataFactoryClass *class)
150 {
151         GObjectClass *object_class;
152
153         g_type_class_add_private (class, sizeof (EDataFactoryPrivate));
154
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;
159
160         class->backend_factory_type = E_TYPE_BACKEND_FACTORY;
161
162         /**
163          * EDataFactory::backend-created:
164          * @data_factory: the #EDataFactory which emitted the signal
165          * @backend: the newly-created #EBackend
166          *
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.
170          *
171          * Since: 3.8
172          **/
173         signals[BACKEND_CREATED] = g_signal_new (
174                 "backend-created",
175                 G_OBJECT_CLASS_TYPE (object_class),
176                 G_SIGNAL_RUN_LAST,
177                 G_STRUCT_OFFSET (EDataFactoryClass, backend_created),
178                 NULL, NULL, NULL,
179                 G_TYPE_NONE, 1,
180                 E_TYPE_BACKEND);
181 }
182
183 static void
184 e_data_factory_init (EDataFactory *data_factory)
185 {
186         data_factory->priv = E_DATA_FACTORY_GET_PRIVATE (data_factory);
187
188         g_mutex_init (&data_factory->priv->mutex);
189
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);
195
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);
201 }
202
203 /**
204  * e_data_factory_ref_backend:
205  * @data_factory: an #EDataFactory
206  * @hash_key: hash key for an #EBackendFactory
207  * @source: an #ESource
208  *
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.
212  *
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.
218  *
219  * If no suitable #EBackendFactory exists, the function returns %NULL.
220  *
221  * Returns: an #EBackend for @source, or %NULL
222  *
223  * Since: 3.6
224  **/
225 EBackend *
226 e_data_factory_ref_backend (EDataFactory *data_factory,
227                             const gchar *hash_key,
228                             ESource *source)
229 {
230         return e_data_factory_ref_initable_backend (
231                 data_factory, hash_key, source, NULL, NULL);
232 }
233
234 /**
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
241  *
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.
245  *
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.
249  *
250  * If the newly-created backend implements the #GInitable interface, then
251  * g_initable_init() is also called on it using @cancellable and @error.
252  *
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.
258  *
259  * If no suitable #EBackendFactory exists, or if the #EBackend fails to
260  * initialize, the function sets @error and returns %NULL.
261  *
262  * Returns: an #EBackend for @source, or %NULL
263  *
264  * Since: 3.8
265  **/
266 EBackend *
267 e_data_factory_ref_initable_backend (EDataFactory *data_factory,
268                                      const gchar *hash_key,
269                                      ESource *source,
270                                      GCancellable *cancellable,
271                                      GError **error)
272 {
273         EBackendFactory *backend_factory;
274         GWeakRef *weak_ref;
275         EBackend *backend;
276         const gchar *uid;
277
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);
281
282         uid = e_source_get_uid (source);
283         g_return_val_if_fail (uid != NULL, NULL);
284
285         g_mutex_lock (&data_factory->priv->mutex);
286
287         /* The weak ref is already inserted in the hash table. */
288         weak_ref = data_factory_backends_lookup (data_factory, uid);
289
290         /* Check if we already have a backend for the given source. */
291         backend = g_weak_ref_get (weak_ref);
292
293         if (backend != NULL)
294                 goto exit;
295
296         /* Find a suitable backend factory using the hash key. */
297         backend_factory =
298                 e_data_factory_ref_backend_factory (data_factory, hash_key);
299
300         if (backend_factory == NULL) {
301                 g_set_error (
302                         error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
303                         _("No backend factory for hash key '%s'"),
304                         hash_key);
305                 goto exit;
306         }
307
308         /* Create a new backend for the given source and store it. */
309         backend = e_backend_factory_new_backend (backend_factory, source);
310
311         if (G_IS_INITABLE (backend)) {
312                 GInitable *initable = G_INITABLE (backend);
313
314                 if (!g_initable_init (initable, cancellable, error)) {
315                         g_object_unref (backend);
316                         backend = NULL;
317                 }
318         }
319
320         /* This still does the right thing if backend is NULL. */
321         g_weak_ref_set (weak_ref, backend);
322
323         g_object_unref (backend_factory);
324
325         if (backend != NULL)
326                 g_signal_emit (
327                         data_factory, signals[BACKEND_CREATED], 0, backend);
328
329 exit:
330         g_mutex_unlock (&data_factory->priv->mutex);
331
332         return backend;
333 }
334
335 /**
336  * e_data_factory_ref_backend_factory:
337  * @data_factory: an #EDataFactory
338  * @hash_key: hash key for an #EBackendFactory
339  *
340  * Returns the #EBackendFactory for @hash_key, or %NULL if no such factory
341  * is registered.
342  *
343  * The returned #EBackendFactory is referenced for thread-safety.
344  * Unreference the #EBackendFactory with g_object_unref() when finished
345  * with it.
346  *
347  * Returns: the #EBackendFactory for @hash_key, or %NULL
348  *
349  * Since: 3.6
350  **/
351 EBackendFactory *
352 e_data_factory_ref_backend_factory (EDataFactory *data_factory,
353                                     const gchar *hash_key)
354 {
355         GHashTable *backend_factories;
356         EBackendFactory *backend_factory;
357
358         g_return_val_if_fail (E_IS_DATA_FACTORY (data_factory), NULL);
359         g_return_val_if_fail (hash_key != NULL, NULL);
360
361         /* It should be safe to lookup backend factories without a mutex
362          * because once initially populated the hash table remains fixed.
363          *
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. */
367
368         backend_factories = data_factory->priv->backend_factories;
369         backend_factory = g_hash_table_lookup (backend_factories, hash_key);
370
371         if (backend_factory != NULL)
372                 g_object_ref (backend_factory);
373
374         return backend_factory;
375 }
376