4f94e4a7423bffe442024e7905612b3b5d4b632a
[profile/ivi/gsignond.git] / src / daemon / plugins / gsignond-plugin-proxy-factory.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of gsignond
5  *
6  * Copyright (C) 2012 Intel Corporation.
7  *
8  * Contact: Alexander Kanavin <alex.kanavin@gmail.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23  * 02110-1301 USA
24  */
25
26 #include <string.h>
27 #include <stdio.h>
28
29 #include "gsignond/gsignond-log.h"
30 #include "common/gsignond-plugin-loader.h"
31 #include "gsignond-plugin-proxy-factory.h"
32 #include "gsignond-plugin-remote.h"
33
34 G_DEFINE_TYPE (GSignondPluginProxyFactory, gsignond_plugin_proxy_factory, G_TYPE_OBJECT);
35
36
37 enum
38 {
39     PROP_0,
40     
41     PROP_CONFIG,
42     
43     N_PROPERTIES
44 };
45
46 static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
47
48 static void _enumerate_plugins(GSignondPluginProxyFactory* self)
49 {
50     GDir* plugin_dir = g_dir_open(gsignond_config_get_string (self->config, 
51         GSIGNOND_CONFIG_GENERAL_PLUGINS_DIR), 0, NULL);
52     if (plugin_dir == NULL) {
53         WARN ("plugin directory empty");
54         return;
55     }
56         
57     int n_plugins = 0;
58     while (g_dir_read_name(plugin_dir) != NULL)
59         n_plugins++;
60     g_dir_rewind(plugin_dir);
61     
62     self->methods = g_malloc0(sizeof(gchar*) * (n_plugins + 1));
63
64     DBG ("enumerate plugins in %s (factory=%p)",
65          gsignond_config_get_string (self->config,
66                                      GSIGNOND_CONFIG_GENERAL_PLUGINS_DIR),
67                                      self
68         );
69     gchar **method_iter = self->methods;
70     while (1) {
71         const gchar* plugin_soname = g_dir_read_name(plugin_dir);
72         if (plugin_soname == NULL)
73             break;
74         if (g_str_has_prefix(plugin_soname, "lib") && 
75             g_str_has_suffix(plugin_soname, ".so")) {
76             gchar* plugin_name = g_strndup(plugin_soname+3, 
77                 strlen(plugin_soname) - 6);
78             GSignondPlugin* plugin = GSIGNOND_PLUGIN (
79                     gsignond_plugin_remote_new (self->config, plugin_name));
80             if (plugin != NULL) {
81                 gchar* plugin_type;
82                 gchar** mechanisms;
83                 g_object_get(plugin, 
84                             "type", &plugin_type, 
85                             "mechanisms", &mechanisms, 
86                              NULL);
87                 if (g_strcmp0 (plugin_type, plugin_name) == 0) {
88                     *method_iter = plugin_type;
89                     method_iter++;
90                     g_hash_table_insert(self->mechanisms,
91                         plugin_type, mechanisms);
92                 } else {
93                     g_free(plugin_type);
94                     g_strfreev(mechanisms);
95                 }
96                 g_object_unref(plugin);
97             }
98             g_free(plugin_name);
99         }
100     }
101     g_dir_close(plugin_dir);
102 }
103
104 static GObject *
105 gsignond_plugin_proxy_factory_constructor (GType                  gtype,
106                                    guint                  n_properties,
107                                    GObjectConstructParam *properties)
108 {
109   GObject *obj;
110
111   {
112     /* Always chain up to the parent constructor */
113     obj = G_OBJECT_CLASS (gsignond_plugin_proxy_factory_parent_class)->constructor (
114         gtype, n_properties, properties);
115   }
116   
117   return obj;
118 }
119
120 static void
121 gsignond_plugin_proxy_factory_set_property (GObject      *object,
122                                        guint         property_id,
123                                        const GValue *value,
124                                        GParamSpec   *pspec)
125 {
126     GSignondPluginProxyFactory *self = GSIGNOND_PLUGIN_PROXY_FACTORY (object);
127     switch (property_id)
128     {
129         case PROP_CONFIG:
130             g_assert (self->config == NULL);
131             self->config = g_value_dup_object (value);
132             break;
133         default:
134             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
135             break;
136     }
137 }
138
139 static void
140 gsignond_plugin_proxy_factory_get_property (GObject    *object,
141                                        guint       prop_id,
142                                        GValue     *value,
143                                        GParamSpec *pspec)
144 {
145     GSignondPluginProxyFactory *self = GSIGNOND_PLUGIN_PROXY_FACTORY (object);
146     
147     switch (prop_id)
148     {
149         case PROP_CONFIG:
150             g_value_set_object (value, self->config);
151             break;
152         default:
153             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
154             break;
155     }
156 }
157
158 static void
159 gsignond_plugin_proxy_factory_dispose (GObject *gobject)
160 {
161     GSignondPluginProxyFactory *self = GSIGNOND_PLUGIN_PROXY_FACTORY (gobject);
162
163     if (self->config) {
164         g_object_unref (self->config);
165         self->config = NULL;
166     }
167
168   /* Chain up to the parent class */
169   G_OBJECT_CLASS (gsignond_plugin_proxy_factory_parent_class)->dispose (gobject);
170 }
171
172 static void
173 gsignond_plugin_proxy_factory_finalize (GObject *gobject)
174 {
175     GSignondPluginProxyFactory *self = GSIGNOND_PLUGIN_PROXY_FACTORY (gobject);
176
177     if (self->plugins) {
178         g_hash_table_destroy (self->plugins);
179         self->plugins = NULL;
180     }
181     if (self->mechanisms) {
182         g_hash_table_destroy (self->mechanisms);
183         self->mechanisms = NULL;
184     }
185     if (self->methods) {
186         g_free (self->methods);
187         self->methods = NULL;
188     }
189
190     /* Chain up to the parent class */
191     G_OBJECT_CLASS (gsignond_plugin_proxy_factory_parent_class)->finalize (gobject);
192 }
193
194
195 static void
196 gsignond_plugin_proxy_factory_class_init (GSignondPluginProxyFactoryClass *klass)
197 {
198     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
199     
200     gobject_class->constructor = gsignond_plugin_proxy_factory_constructor;
201     gobject_class->set_property = gsignond_plugin_proxy_factory_set_property;
202     gobject_class->get_property = gsignond_plugin_proxy_factory_get_property;
203     gobject_class->dispose = gsignond_plugin_proxy_factory_dispose;
204     gobject_class->finalize = gsignond_plugin_proxy_factory_finalize;
205
206     obj_properties[PROP_CONFIG] = g_param_spec_object ("config",
207                                                        "config",
208                                                        "Configuration object",
209                                                        GSIGNOND_TYPE_CONFIG,
210                                                        G_PARAM_CONSTRUCT_ONLY |
211                                                        G_PARAM_READWRITE |
212                                                        G_PARAM_STATIC_STRINGS);
213     
214
215     g_object_class_install_properties (gobject_class,
216                                        N_PROPERTIES,
217                                        obj_properties);
218 }
219
220 static void
221 gsignond_plugin_proxy_factory_init (GSignondPluginProxyFactory *self)
222 {
223     self->mechanisms = g_hash_table_new_full((GHashFunc)g_str_hash,
224                                              (GEqualFunc)g_str_equal,
225                                              (GDestroyNotify)g_free,
226                                              (GDestroyNotify)g_strfreev);
227
228     self->plugins = g_hash_table_new_full ((GHashFunc)g_str_hash,
229                                            (GEqualFunc)g_str_equal,
230                                            (GDestroyNotify)g_free,
231                                            (GDestroyNotify)g_object_unref);
232
233     self->methods = NULL;
234 }
235
236 GSignondPluginProxyFactory* 
237 gsignond_plugin_proxy_factory_new(GSignondConfig *config)
238 {
239     GSignondPluginProxyFactory* proxy = g_object_new(
240                                               GSIGNOND_TYPE_PLUGIN_PROXY_FACTORY,
241                                               "config", config,
242                                               NULL);
243     return proxy;
244 }
245
246 static gboolean
247 _find_proxy_by_pointer (gpointer key, gpointer value, gpointer userdata)
248 {
249     if (userdata == value) {
250         g_free (key);
251         return TRUE;
252     }
253     return FALSE;
254 }
255
256 static void
257 _remove_dead_proxy (gpointer data, GObject *dead_proxy)
258 {
259     GSignondPluginProxyFactory *factory = GSIGNOND_PLUGIN_PROXY_FACTORY(data);
260     if (factory) {
261         g_hash_table_foreach_steal (factory->plugins, 
262                 _find_proxy_by_pointer, dead_proxy);
263     }
264 }
265
266 static void
267 _proxy_toggle_ref_cb (gpointer userdata, GObject *proxy, gboolean is_last_ref)
268 {
269     /* start/stop timeout timer */
270     gsignond_disposable_set_auto_dispose (GSIGNOND_DISPOSABLE (proxy), is_last_ref);
271
272     if (is_last_ref) g_object_weak_ref (proxy, _remove_dead_proxy, userdata);
273     else g_object_weak_unref (proxy, _remove_dead_proxy, userdata);
274 }
275
276 GSignondPluginProxy*
277 gsignond_plugin_proxy_factory_get_plugin(GSignondPluginProxyFactory* factory,
278                                          const gchar* plugin_type)
279 {
280     g_return_val_if_fail (factory && GSIGNOND_IS_PLUGIN_PROXY_FACTORY(factory), NULL);
281     g_return_val_if_fail (plugin_type, NULL);
282
283     GSignondPluginProxy* proxy = NULL;
284
285     if (factory->methods == NULL) {
286         _enumerate_plugins (factory);
287     }
288
289     if (g_hash_table_lookup(factory->mechanisms, plugin_type) == NULL) {
290         DBG("Plugin not known %s", plugin_type);
291         return NULL;
292     }
293
294     proxy = g_hash_table_lookup(factory->plugins, plugin_type);
295     if (proxy != NULL) {
296         DBG("get existing plugin %s -> %p", plugin_type, proxy);
297         g_object_ref(proxy);
298         return proxy;
299     }
300
301     proxy = gsignond_plugin_proxy_new(factory->config, plugin_type);
302     if (proxy == NULL) {
303         return NULL;
304     }
305     g_hash_table_insert(factory->plugins, g_strdup (plugin_type), proxy);
306     DBG("get new plugin %s -> %p", plugin_type, proxy);
307     g_object_add_toggle_ref(G_OBJECT(proxy), _proxy_toggle_ref_cb, factory);
308
309     return proxy;
310 }
311
312 gboolean gsignond_plugin_proxy_factory_add_plugin(
313     GSignondPluginProxyFactory* factory,
314     GSignondPluginProxy* proxy)
315 {
316     g_return_val_if_fail (factory && GSIGNOND_IS_PLUGIN_PROXY_FACTORY(factory), FALSE);
317     g_return_val_if_fail (proxy && GSIGNOND_IS_PLUGIN_PROXY(proxy), FALSE);
318     
319     gchar* plugin_type = NULL;
320     g_object_get (proxy, "type", &plugin_type, NULL);
321
322     if (g_hash_table_contains(factory->plugins, plugin_type)) {
323         g_free(plugin_type);
324         return FALSE;
325     }
326     g_object_ref(proxy);
327     DBG("add plugin %s -> %p", plugin_type, proxy);
328     g_hash_table_insert(factory->plugins, plugin_type, proxy);
329
330     return TRUE;
331 }
332
333 const gchar** 
334 gsignond_plugin_proxy_factory_get_plugin_types(
335    GSignondPluginProxyFactory* factory)
336 {
337         if (factory->methods == NULL) {
338                 _enumerate_plugins (factory);
339         }
340     return (const gchar**)factory->methods;
341 }
342    
343 const gchar**
344 gsignond_plugin_proxy_factory_get_plugin_mechanisms(
345    GSignondPluginProxyFactory* factory, const gchar* plugin_type)
346 {
347     g_return_val_if_fail(factory->mechanisms, NULL);
348
349     if (factory->methods == NULL) {
350         _enumerate_plugins (factory);
351     }
352
353     return g_hash_table_lookup(factory->mechanisms, plugin_type);
354 }