Imported Upstream version 0.20.12
[profile/ivi/GUPnP.git] / libgupnp / gupnp-resource-factory.c
1 /*
2  * Copyright (C) 2007 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
3  * Copyright (C) 2006, 2007 OpenedHand Ltd.
4  *
5  * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
6  *         Jorn Baayen <jorn@openedhand.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 /**
25  * SECTION:gupnp-resource-factory
26  * @short_description: Class for resource and resource proxy object creation.
27  *
28  * #GUPnPResourceFactory objects are used by #GUPnPControlPoint,
29  * #GUPnPDeviceProxy and #GUPnPDevice to create resource proxy and resource
30  * objects. Register UPnP type - #GType pairs to have resource or resource proxy
31  * objects created with the specified #GType whenever an object for a resource
32  * of the specified UPnP type is requested. The #GType<!-- -->s need
33  * to be derived from the relevant resource or resource proxy type (e.g.
34  * a device proxy type needs to be derived from #GUPnPDeviceProxy).
35  */
36
37 #include <string.h>
38
39 #include "gupnp-resource-factory-private.h"
40 #include "gupnp-root-device.h"
41
42 G_DEFINE_TYPE (GUPnPResourceFactory,
43                gupnp_resource_factory,
44                G_TYPE_OBJECT);
45
46 struct _GUPnPResourceFactoryPrivate {
47         GHashTable *resource_type_hash;
48         GHashTable *proxy_type_hash;
49 };
50
51 static void
52 gupnp_resource_factory_init (GUPnPResourceFactory *factory)
53 {
54         factory->priv =
55                 G_TYPE_INSTANCE_GET_PRIVATE (factory,
56                                              GUPNP_TYPE_RESOURCE_FACTORY,
57                                              GUPnPResourceFactoryPrivate);
58
59         factory->priv->resource_type_hash =
60                         g_hash_table_new_full (g_str_hash,
61                                                g_str_equal,
62                                                g_free,
63                                                NULL);
64         factory->priv->proxy_type_hash =
65                         g_hash_table_new_full (g_str_hash,
66                                                g_str_equal,
67                                                g_free,
68                                                NULL);
69 }
70
71 static void
72 gupnp_resource_factory_finalize (GObject *object)
73 {
74         GUPnPResourceFactory *self;
75         GObjectClass *object_class;
76
77         self = GUPNP_RESOURCE_FACTORY (object);
78
79         if (self->priv->resource_type_hash) {
80                 g_hash_table_destroy (self->priv->resource_type_hash);
81                 self->priv->resource_type_hash = NULL;
82         }
83
84         if (self->priv->proxy_type_hash) {
85                 g_hash_table_destroy (self->priv->proxy_type_hash);
86                 self->priv->proxy_type_hash = NULL;
87         }
88
89         object_class = G_OBJECT_CLASS (gupnp_resource_factory_parent_class);
90         object_class->finalize (object);
91 }
92
93 static void
94 gupnp_resource_factory_class_init (GUPnPResourceFactoryClass *klass)
95 {
96         GObjectClass *object_class;
97
98         object_class = G_OBJECT_CLASS (klass);
99
100         object_class->finalize = gupnp_resource_factory_finalize;
101
102         g_type_class_add_private (klass, sizeof (GUPnPResourceFactoryPrivate));
103 }
104
105 /**
106  * gupnp_resource_factory_new:
107  *
108  * Create a new #GUPnPResourceFactory object.
109  *
110  * Return value: A #GUPnPResourceFactory object.
111  **/
112 GUPnPResourceFactory *
113 gupnp_resource_factory_new (void)
114 {
115         return g_object_new (GUPNP_TYPE_RESOURCE_FACTORY, NULL);
116 }
117
118 /**
119  * gupnp_resource_factory_get_default:
120  *
121  * Get the default singleton #GUPnPResourceFactory object.
122  *
123  * Returns: (transfer none): A @GUPnPResourceFactory object.
124  **/
125 GUPnPResourceFactory *
126 gupnp_resource_factory_get_default (void)
127 {
128         static GUPnPResourceFactory *default_factory = NULL;
129
130         if (G_UNLIKELY (default_factory == NULL)) {
131                 default_factory = g_object_new (GUPNP_TYPE_RESOURCE_FACTORY,
132                                                 NULL);
133         }
134
135         return default_factory;
136 }
137
138 /**
139  * gupnp_resource_factory_create_device_proxy:
140  * @factory: A #GUPnPResourceFactory
141  * @context: A #GUPnPContext
142  * @doc: A #GUPnPXMLDoc
143  * @element: The #xmlNode ponting to the right device element
144  * @udn: The UDN of the device to create a proxy for
145  * @location: The location of the device description file
146  * @url_base: The URL base for this device, or %NULL if none
147  *
148  *
149  * Create a #GUPnPDeviceProxy for the device with element @element, as
150  * read from the device description file specified by @location.
151  *
152  * Return value: A new #GUPnPDeviceProxy.
153  **/
154 GUPnPDeviceProxy *
155 gupnp_resource_factory_create_device_proxy
156                                 (GUPnPResourceFactory *factory,
157                                  GUPnPContext         *context,
158                                  GUPnPXMLDoc          *doc,
159                                  xmlNode              *element,
160                                  const char           *udn,
161                                  const char           *location,
162                                  const SoupURI        *url_base)
163 {
164         GUPnPDeviceProxy *proxy;
165         char             *upnp_type;
166         GType             proxy_type = GUPNP_TYPE_DEVICE_PROXY;
167
168         g_return_val_if_fail (GUPNP_IS_RESOURCE_FACTORY (factory), NULL);
169         g_return_val_if_fail (GUPNP_IS_CONTEXT (context), NULL);
170         g_return_val_if_fail (GUPNP_IS_XML_DOC (doc), NULL);
171         g_return_val_if_fail (element != NULL, NULL);
172         g_return_val_if_fail (location != NULL, NULL);
173         g_return_val_if_fail (url_base != NULL, NULL);
174
175         upnp_type = xml_util_get_child_element_content_glib (element,
176                                                              "deviceType");
177         if (upnp_type) {
178                 gpointer value;
179
180                 value = g_hash_table_lookup (factory->priv->proxy_type_hash,
181                                              upnp_type);
182                 if (value)
183                         proxy_type = GPOINTER_TO_SIZE (value);
184
185                 g_free (upnp_type);
186         }
187
188         proxy = g_object_new (proxy_type,
189                               "resource-factory", factory,
190                               "context", context,
191                               "location", location,
192                               "udn", udn,
193                               "url-base", url_base,
194                               "document", doc,
195                               "element", element,
196                               NULL);
197
198         return proxy;
199 }
200
201 /**
202  * gupnp_resource_factory_create_service_proxy:
203  * @factory: A #GUPnPResourceFactory
204  * @context: A #GUPnPContext
205  * @doc: A #GUPnPXMLDoc
206  * @element: The #xmlNode ponting to the right service element
207  * @location: The location of the service description file
208  * @udn: The UDN of the device the service is contained in
209  * @service_type: (allow-none): The service type, or %NULL to use service
210  * type from @element
211  * @url_base: The URL base for this service, or %NULL if none
212  *
213  * Create a #GUPnPServiceProxy for the service with element @element, as
214  * read from the service description file specified by @location.
215  *
216  * Return value: A new #GUPnPServiceProxy.
217  **/
218 GUPnPServiceProxy *
219 gupnp_resource_factory_create_service_proxy
220                                 (GUPnPResourceFactory *factory,
221                                  GUPnPContext         *context,
222                                  GUPnPXMLDoc          *doc,
223                                  xmlNode              *element,
224                                  const char           *udn,
225                                  const char           *service_type,
226                                  const char           *location,
227                                  const SoupURI        *url_base)
228 {
229         char              *type_from_xml = NULL;
230         GUPnPServiceProxy *proxy;
231         GType              proxy_type = GUPNP_TYPE_SERVICE_PROXY;
232
233         g_return_val_if_fail (GUPNP_IS_RESOURCE_FACTORY (factory), NULL);
234         g_return_val_if_fail (GUPNP_IS_CONTEXT (context), NULL);
235         g_return_val_if_fail (GUPNP_IS_XML_DOC (doc), NULL);
236         g_return_val_if_fail (element != NULL, NULL);
237         g_return_val_if_fail (location != NULL, NULL);
238         g_return_val_if_fail (url_base != NULL, NULL);
239
240         if (!service_type) {
241                 type_from_xml =
242                     xml_util_get_child_element_content_glib (element,
243                                                              "serviceType");
244                 service_type = type_from_xml;
245         }
246
247         if (service_type) {
248                 gpointer value;
249
250                 value = g_hash_table_lookup (factory->priv->proxy_type_hash,
251                                              service_type);
252                 if (value)
253                         proxy_type = GPOINTER_TO_SIZE (value);
254         }
255
256         proxy = g_object_new (proxy_type,
257                               "context", context,
258                               "location", location,
259                               "udn", udn,
260                               "service-type", service_type,
261                               "url-base", url_base,
262                               "document", doc,
263                               "element", element,
264                               NULL);
265
266         g_free (type_from_xml);
267
268         return proxy;
269 }
270
271 /**
272  * gupnp_resource_factory_create_device:
273  * @factory: A #GUPnPResourceFactory
274  * @context: A #GUPnPContext
275  * @root_device: The #GUPnPRootDevice
276  * @element: The #xmlNode ponting to the right device element
277  * @udn: The UDN of the device to create a device for
278  * @location: The location of the device description file
279  * @url_base: The URL base for this device
280  *
281  * Create a #GUPnPDevice for the device with element @element, as
282  * read from the device description file specified by @location.
283  *
284  * Return value: A new #GUPnPDevice.
285  **/
286 GUPnPDevice *
287 gupnp_resource_factory_create_device
288                                 (GUPnPResourceFactory *factory,
289                                  GUPnPContext         *context,
290                                  GUPnPDevice          *root_device,
291                                  xmlNode              *element,
292                                  const char           *udn,
293                                  const char           *location,
294                                  const SoupURI        *url_base)
295 {
296         GUPnPDevice *device;
297         char        *upnp_type;
298         GType        device_type = GUPNP_TYPE_DEVICE;
299
300         g_return_val_if_fail (GUPNP_IS_RESOURCE_FACTORY (factory), NULL);
301         g_return_val_if_fail (GUPNP_IS_CONTEXT (context), NULL);
302         g_return_val_if_fail (GUPNP_IS_ROOT_DEVICE (root_device), NULL);
303         g_return_val_if_fail (element != NULL, NULL);
304         g_return_val_if_fail (url_base != NULL, NULL);
305
306         upnp_type = xml_util_get_child_element_content_glib (element,
307                                                              "deviceType");
308         if (upnp_type) {
309                 gpointer value;
310
311                 value = g_hash_table_lookup (factory->priv->resource_type_hash,
312                                              upnp_type);
313                 if (value)
314                         device_type = GPOINTER_TO_SIZE (value);
315
316                 g_free (upnp_type);
317         }
318
319         device = g_object_new (device_type,
320                                "resource-factory", factory,
321                                "context", context,
322                                "root-device", root_device,
323                                "location", location,
324                                "udn", udn,
325                                "url-base", url_base,
326                                "element", element,
327                                NULL);
328
329         return device;
330 }
331
332 /**
333  * gupnp_resource_factory_create_service:
334  * @factory: A #GUPnPResourceFactory
335  * @context: A #GUPnPContext
336  * @root_device: The #GUPnPRootDevice
337  * @element: The #xmlNode ponting to the right service element
338  * @udn: The UDN of the device the service is contained in
339  * @location: The location of the service description file
340  * @url_base: The URL base for this service
341  *
342  * Create a #GUPnPService for the service with element @element, as
343  * read from the service description file specified by @location.
344  *
345  * Return value: A new #GUPnPService.
346  **/
347 GUPnPService *
348 gupnp_resource_factory_create_service
349                                 (GUPnPResourceFactory *factory,
350                                  GUPnPContext         *context,
351                                  GUPnPDevice          *root_device,
352                                  xmlNode              *element,
353                                  const char           *udn,
354                                  const char           *location,
355                                  const SoupURI        *url_base)
356 {
357         GUPnPService *service;
358         char         *upnp_type;
359         GType         service_type = GUPNP_TYPE_SERVICE;
360
361         g_return_val_if_fail (GUPNP_IS_RESOURCE_FACTORY (factory), NULL);
362         g_return_val_if_fail (GUPNP_IS_CONTEXT (context), NULL);
363         g_return_val_if_fail (GUPNP_IS_ROOT_DEVICE (root_device), NULL);
364         g_return_val_if_fail (element != NULL, NULL);
365         g_return_val_if_fail (location != NULL, NULL);
366         g_return_val_if_fail (url_base != NULL, NULL);
367
368         upnp_type = xml_util_get_child_element_content_glib (element,
369                                                              "serviceType");
370         if (upnp_type) {
371                 gpointer value;
372
373                 value = g_hash_table_lookup (factory->priv->resource_type_hash,
374                                              upnp_type);
375                 if (value)
376                         service_type = GPOINTER_TO_SIZE (value);
377
378                 g_free (upnp_type);
379         }
380
381         service = g_object_new (service_type,
382                                 "context", context,
383                                 "root-device", root_device,
384                                 "location", location,
385                                 "udn", udn,
386                                 "url-base", url_base,
387                                 "element", element,
388                                 NULL);
389
390         return service;
391 }
392
393 /**
394  * gupnp_resource_factory_register_resource_type:
395  * @factory: A #GUPnPResourceFactory.
396  * @upnp_type: The UPnP type name of the resource.
397  * @type: The requested GType assignment for the resource.
398  *
399  * Registers the GType @type for the resource of UPnP type @upnp_type. After
400  * this call, the factory @factory will create object of GType @type each time
401  * it is asked to create a resource object for UPnP type @upnp_type.
402  *
403  * Note: GType @type must be a derived type of #GUPNP_TYPE_DEVICE if resource is
404  * a device or #GUPNP_TYPE_SERVICE if its a service.
405  **/
406 void
407 gupnp_resource_factory_register_resource_type (GUPnPResourceFactory *factory,
408                                                const char           *upnp_type,
409                                                GType                 type)
410 {
411         g_hash_table_insert (factory->priv->resource_type_hash,
412                              g_strdup (upnp_type),
413                              GSIZE_TO_POINTER (type));
414 }
415
416 /**
417  * gupnp_resource_factory_unregister_resource_type:
418  * @factory: A #GUPnPResourceFactory.
419  * @upnp_type: The UPnP type name of the resource.
420  *
421  * Unregisters the GType assignment for the resource of UPnP type @upnp_type.
422  *
423  * Return value: %TRUE if GType assignment was removed successfully, %FALSE
424  * otherwise.
425  **/
426 gboolean
427 gupnp_resource_factory_unregister_resource_type
428                                 (GUPnPResourceFactory *factory,
429                                  const char           *upnp_type)
430 {
431         return g_hash_table_remove (factory->priv->resource_type_hash,
432                                     upnp_type);
433 }
434
435 /**
436  * gupnp_resource_factory_register_resource_proxy_type:
437  * @factory: A #GUPnPResourceFactory.
438  * @upnp_type: The UPnP type name of the resource.
439  * @type: The requested GType assignment for the resource proxy.
440  *
441  * Registers the GType @type for the proxy of resource of UPnP type @upnp_type.
442  * After this call, the factory @factory will create object of GType @type each
443  * time it is asked to create a resource proxy object for UPnP type @upnp_type.
444  *
445  * Note: GType @type must be a derived type of #GUPNP_TYPE_DEVICE_PROXY if
446  * resource is a device or #GUPNP_TYPE_SERVICE_PROXY if its a service.
447  **/
448 void
449 gupnp_resource_factory_register_resource_proxy_type
450                                 (GUPnPResourceFactory *factory,
451                                  const char           *upnp_type,
452                                  GType                 type)
453 {
454         g_hash_table_insert (factory->priv->proxy_type_hash,
455                              g_strdup (upnp_type),
456                              GSIZE_TO_POINTER (type));
457 }
458
459 /**
460  * gupnp_resource_factory_unregister_resource_proxy_type:
461  * @factory: A #GUPnPResourceFactory.
462  * @upnp_type: The UPnP type name of the resource.
463  *
464  * Unregisters the GType assignment for the proxy of resource of UPnP type
465  * @upnp_type.
466  *
467  * Return value: %TRUE if GType assignment was removed successfully, %FALSE
468  * otherwise.
469  **/
470 gboolean
471 gupnp_resource_factory_unregister_resource_proxy_type
472                                 (GUPnPResourceFactory *factory,
473                                  const char           *upnp_type)
474 {
475         return g_hash_table_remove (factory->priv->proxy_type_hash, upnp_type);
476 }