gupnp-resource-factory.c 17.2 KB
Newer Older
1
/*
2
 * Copyright (C) 2007 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
3
4
 * Copyright (C) 2006, 2007 OpenedHand Ltd.
 *
5
 * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 *         Jorn Baayen <jorn@openedhand.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/**
 * SECTION:gupnp-resource-factory
26
 * @short_description: Class for resource and resource proxy object creation.
27
 *
28
29
30
31
32
33
34
 * #GUPnPResourceFactory objects are used by #GUPnPControlPoint,
 * #GUPnPDeviceProxy and #GUPnPDevice to create resource proxy and resource
 * objects. Register UPnP type - #GType pairs to have resource or resource proxy
 * objects created with the specified #GType whenever an object for a resource
 * of the specified UPnP type is requested. The #GType<!-- -->s need
 * to be derived from the relevant resource or resource proxy type (e.g.
 * a device proxy type needs to be derived from #GUPnPDeviceProxy).
35
36
37
38
 */

#include <string.h>

39
#include "gupnp-resource-factory-private.h"
40
41
42
43
44
45
#include "gupnp-root-device.h"

G_DEFINE_TYPE (GUPnPResourceFactory,
               gupnp_resource_factory,
               G_TYPE_OBJECT);

46
47
48
49
50
struct _GUPnPResourceFactoryPrivate {
        GHashTable *resource_type_hash;
        GHashTable *proxy_type_hash;
};

51
52
53
static void
gupnp_resource_factory_init (GUPnPResourceFactory *factory)
{
54
55
56
57
58
59
60
        factory->priv =
                G_TYPE_INSTANCE_GET_PRIVATE (factory,
                                             GUPNP_TYPE_RESOURCE_FACTORY,
                                             GUPnPResourceFactoryPrivate);

        factory->priv->resource_type_hash =
                        g_hash_table_new_full (g_str_hash,
61
                                               g_str_equal,
62
63
64
65
                                               g_free,
                                               NULL);
        factory->priv->proxy_type_hash =
                        g_hash_table_new_full (g_str_hash,
66
                                               g_str_equal,
67
68
                                               g_free,
                                               NULL);
69
70
}

71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
static void
gupnp_resource_factory_finalize (GObject *object)
{
        GUPnPResourceFactory *self;
        GObjectClass *object_class;

        self = GUPNP_RESOURCE_FACTORY (object);

        if (self->priv->resource_type_hash) {
                g_hash_table_destroy (self->priv->resource_type_hash);
                self->priv->resource_type_hash = NULL;
        }

        if (self->priv->proxy_type_hash) {
                g_hash_table_destroy (self->priv->proxy_type_hash);
                self->priv->proxy_type_hash = NULL;
        }

        object_class = G_OBJECT_CLASS (gupnp_resource_factory_parent_class);
        object_class->finalize (object);
}

93
94
static void
gupnp_resource_factory_class_init (GUPnPResourceFactoryClass *klass)
95
{
96
97
98
99
100
101
        GObjectClass *object_class;

        object_class = G_OBJECT_CLASS (klass);

        object_class->finalize = gupnp_resource_factory_finalize;

102
        g_type_class_add_private (klass, sizeof (GUPnPResourceFactoryPrivate));
103
104
}

105
/**
106
 * gupnp_resource_factory_new:
107
 *
108
109
110
 * Create a new #GUPnPResourceFactory object.
 *
 * Return value: A #GUPnPResourceFactory object.
111
112
113
 **/
GUPnPResourceFactory *
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
122
123
 * Get the default singleton #GUPnPResourceFactory object.
 *
 * Return value: A @GUPnPResourceFactory object.
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
 **/
GUPnPResourceFactory *
gupnp_resource_factory_get_default (void)
{
        static GUPnPResourceFactory *default_factory = NULL;

        if (G_UNLIKELY (default_factory == NULL)) {
                default_factory = g_object_new (GUPNP_TYPE_RESOURCE_FACTORY,
                                                NULL);
        }

        return default_factory;
}

/**
139
 * gupnp_resource_factory_create_device_proxy:
140
141
 * @factory: A #GUPnPResourceFactory
 * @context: A #GUPnPContext
142
 * @doc: A #GUPnPXMLDoc
143
144
145
 * @element: The #xmlNode ponting to the right device element
 * @udn: The UDN of the device to create a proxy for
 * @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
155
156
157
 **/
GUPnPDeviceProxy *
gupnp_resource_factory_create_device_proxy
                                (GUPnPResourceFactory *factory,
                                 GUPnPContext         *context,
158
                                 GUPnPXMLDoc          *doc,
159
160
161
                                 xmlNode              *element,
                                 const char           *udn,
                                 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
172
173
        g_return_val_if_fail (element != NULL, NULL);
        g_return_val_if_fail (location != NULL, NULL);
        g_return_val_if_fail (url_base != NULL, NULL);
174

175
176
177
178
179
180
181
182
        upnp_type = xml_util_get_child_element_content_glib (element,
                                                             "deviceType");
        if (upnp_type) {
                gpointer value;

                value = g_hash_table_lookup (factory->priv->proxy_type_hash,
                                             upnp_type);
                if (value)
183
                        proxy_type = GPOINTER_TO_SIZE (value);
184
185

                g_free (upnp_type);
186
187
188
189
190
191
192
193
194
195
196
197
198
        }

        proxy = g_object_new (proxy_type,
                              "resource-factory", factory,
                              "context", context,
                              "location", location,
                              "udn", udn,
                              "url-base", url_base,
                              "document", doc,
                              "element", element,
                              NULL);

        return proxy;
199
200
201
}

/**
202
 * gupnp_resource_factory_create_service_proxy:
203
204
 * @factory: A #GUPnPResourceFactory
 * @context: A #GUPnPContext
205
 * @doc: A #GUPnPXMLDoc
206
207
208
209
 * @element: The #xmlNode ponting to the right service element
 * @location: The location of the service description file
 * @udn: The UDN of the device the service is contained in
 * @service_type: The service type
210
 * @url_base: The URL base for this service, or %NULL if none
211
 *
212
 * Create a #GUPnPServiceProxy for the service with element @element, as
213
 * read from the service description file specified by @location.
214
215
 *
 * Return value: A new #GUPnPServiceProxy.
216
217
218
219
 **/
GUPnPServiceProxy *
gupnp_resource_factory_create_service_proxy
                                (GUPnPResourceFactory *factory,
220
                                 GUPnPContext         *context,
221
                                 GUPnPXMLDoc          *doc,
222
223
224
225
226
                                 xmlNode              *element,
                                 const char           *udn,
                                 const char           *service_type,
                                 const char           *location,
                                 const SoupURI        *url_base)
227
{
228
229
        GUPnPServiceProxy *proxy;
        GType              proxy_type = GUPNP_TYPE_SERVICE_PROXY;
230
231

        g_return_val_if_fail (GUPNP_IS_RESOURCE_FACTORY (factory), NULL);
232
        g_return_val_if_fail (GUPNP_IS_CONTEXT (context), NULL);
233
        g_return_val_if_fail (GUPNP_IS_XML_DOC (doc), NULL);
234
235
236
237
238
239
        g_return_val_if_fail (element != NULL, NULL);
        g_return_val_if_fail (location != NULL, NULL);
        g_return_val_if_fail (url_base != NULL, NULL);

        if (service_type) {
                gpointer value;
240

241
242
243
                value = g_hash_table_lookup (factory->priv->proxy_type_hash,
                                             service_type);
                if (value)
244
                        proxy_type = GPOINTER_TO_SIZE (value);
245
246
247
248
249
250
251
252
        }

        proxy = g_object_new (proxy_type,
                              "context", context,
                              "location", location,
                              "udn", udn,
                              "service-type", service_type,
                              "url-base", url_base,
253
                              "document", doc,
254
255
256
257
                              "element", element,
                              NULL);

        return proxy;
258
259
260
}

/**
261
 * gupnp_resource_factory_create_device:
262
263
264
265
266
267
268
269
 * @factory: A #GUPnPResourceFactory
 * @context: A #GUPnPContext
 * @root_device: The #GUPnPRootDevice
 * @element: The #xmlNode ponting to the right device element
 * @udn: The UDN of the device to create a device for
 * @location: The location of the device description file
 * @url_base: The URL base for this device
 *
270
 * Create a #GUPnPDevice for the device with element @element, as
271
 * read from the device description file specified by @location.
272
273
 *
 * Return value: A new #GUPnPDevice.
274
275
276
277
278
279
280
281
282
 **/
GUPnPDevice *
gupnp_resource_factory_create_device
                                (GUPnPResourceFactory *factory,
                                 GUPnPContext         *context,
                                 GUPnPDevice          *root_device,
                                 xmlNode              *element,
                                 const char           *udn,
                                 const char           *location,
283
                                 const SoupURI        *url_base)
284
{
285
        GUPnPDevice *device;
286
        char        *upnp_type;
287
        GType        device_type = GUPNP_TYPE_DEVICE;
288
289

        g_return_val_if_fail (GUPNP_IS_RESOURCE_FACTORY (factory), NULL);
290
291
292
293
294
295
296
297
298
299
300
301
302
        g_return_val_if_fail (GUPNP_IS_CONTEXT (context), NULL);
        g_return_val_if_fail (GUPNP_IS_ROOT_DEVICE (root_device), NULL);
        g_return_val_if_fail (element != NULL, NULL);
        g_return_val_if_fail (url_base != NULL, NULL);

        upnp_type = xml_util_get_child_element_content_glib (element,
                                                             "deviceType");
        if (upnp_type) {
                gpointer value;

                value = g_hash_table_lookup (factory->priv->resource_type_hash,
                                             upnp_type);
                if (value)
303
                        device_type = GPOINTER_TO_SIZE (value);
304

305
                g_free (upnp_type);
306
307
308
309
310
311
312
313
314
315
316
        }

        device = g_object_new (device_type,
                               "resource-factory", factory,
                               "context", context,
                               "root-device", root_device,
                               "location", location,
                               "udn", udn,
                               "url-base", url_base,
                               "element", element,
                               NULL);
317

318
        return device;
319
320
321
}

/**
322
 * gupnp_resource_factory_create_service:
323
324
325
326
327
328
329
330
 * @factory: A #GUPnPResourceFactory
 * @context: A #GUPnPContext
 * @root_device: The #GUPnPRootDevice
 * @element: The #xmlNode ponting to the right service element
 * @udn: The UDN of the device the service is contained in
 * @location: The location of the service description file
 * @url_base: The URL base for this service
 *
331
 * Create a #GUPnPService for the service with element @element, as
332
 * read from the service description file specified by @location.
333
334
 *
 * Return value: A new #GUPnPService.
335
336
337
338
339
340
341
342
343
 **/
GUPnPService *
gupnp_resource_factory_create_service
                                (GUPnPResourceFactory *factory,
                                 GUPnPContext         *context,
                                 GUPnPDevice          *root_device,
                                 xmlNode              *element,
                                 const char           *udn,
                                 const char           *location,
344
                                 const SoupURI        *url_base)
345
{
346
        GUPnPService *service;
347
        char         *upnp_type;
348
        GType         service_type = GUPNP_TYPE_SERVICE;
349
350

        g_return_val_if_fail (GUPNP_IS_RESOURCE_FACTORY (factory), NULL);
351
352
353
354
355
356
357
358
359
360
361
362
363
364
        g_return_val_if_fail (GUPNP_IS_CONTEXT (context), NULL);
        g_return_val_if_fail (GUPNP_IS_ROOT_DEVICE (root_device), NULL);
        g_return_val_if_fail (element != NULL, NULL);
        g_return_val_if_fail (location != NULL, NULL);
        g_return_val_if_fail (url_base != NULL, NULL);

        upnp_type = xml_util_get_child_element_content_glib (element,
                                                             "serviceType");
        if (upnp_type) {
                gpointer value;

                value = g_hash_table_lookup (factory->priv->resource_type_hash,
                                             upnp_type);
                if (value)
365
                        service_type = GPOINTER_TO_SIZE (value);
366

367
                g_free (upnp_type);
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
        }

        service = g_object_new (service_type,
                                "context", context,
                                "root-device", root_device,
                                "location", location,
                                "udn", udn,
                                "url-base", url_base,
                                "element", element,
                                NULL);

        return service;
}

/**
383
 * gupnp_resource_factory_register_resource_type:
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
 * @factory: A #GUPnPResourceFactory.
 * @upnp_type: The UPnP type name of the resource.
 * @type: The requested GType assignment for the resource.
 *
 * Registers the GType @type for the resource of UPnP type @upnp_type. After
 * this call, the factory @factory will create object of GType @type each time
 * it is asked to create a resource object for UPnP type @upnp_type.
 *
 * Note: GType @type must be a derived type of #GUPNP_TYPE_DEVICE if resource is
 * a device or #GUPNP_TYPE_SERVICE if its a service.
 **/
void
gupnp_resource_factory_register_resource_type (GUPnPResourceFactory *factory,
                                               const char           *upnp_type,
                                               GType                 type)
{
        g_hash_table_insert (factory->priv->resource_type_hash,
                             g_strdup (upnp_type),
402
                             GSIZE_TO_POINTER (type));
403
404
405
}

/**
406
 * gupnp_resource_factory_unregister_resource_type:
407
408
409
410
411
 * @factory: A #GUPnPResourceFactory.
 * @upnp_type: The UPnP type name of the resource.
 *
 * Unregisters the GType assignment for the resource of UPnP type @upnp_type.
 *
412
 * Return value: %TRUE if GType assignment was removed successfully, %FALSE
413
414
415
416
417
418
419
420
421
422
423
424
 * otherwise.
 **/
gboolean
gupnp_resource_factory_unregister_resource_type
                                (GUPnPResourceFactory *factory,
                                 const char           *upnp_type)
{
        return g_hash_table_remove (factory->priv->resource_type_hash,
                                    upnp_type);
}

/**
425
 * gupnp_resource_factory_register_resource_proxy_type:
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
 * @factory: A #GUPnPResourceFactory.
 * @upnp_type: The UPnP type name of the resource.
 * @type: The requested GType assignment for the resource proxy.
 *
 * Registers the GType @type for the proxy of resource of UPnP type @upnp_type.
 * After this call, the factory @factory will create object of GType @type each
 * time it is asked to create a resource proxy object for UPnP type @upnp_type.
 *
 * Note: GType @type must be a derived type of #GUPNP_TYPE_DEVICE_PROXY if
 * resource is a device or #GUPNP_TYPE_SERVICE_PROXY if its a service.
 **/
void
gupnp_resource_factory_register_resource_proxy_type
                                (GUPnPResourceFactory *factory,
                                 const char           *upnp_type,
                                 GType                 type)
{
        g_hash_table_insert (factory->priv->proxy_type_hash,
                             g_strdup (upnp_type),
445
                             GSIZE_TO_POINTER (type));
446
}
447

448
/**
449
 * gupnp_resource_factory_unregister_resource_proxy_type:
450
451
452
453
454
455
 * @factory: A #GUPnPResourceFactory.
 * @upnp_type: The UPnP type name of the resource.
 *
 * Unregisters the GType assignment for the proxy of resource of UPnP type
 * @upnp_type.
 *
456
 * Return value: %TRUE if GType assignment was removed successfully, %FALSE
457
458
459
460
461
462
463
464
 * otherwise.
 **/
gboolean
gupnp_resource_factory_unregister_resource_proxy_type
                                (GUPnPResourceFactory *factory,
                                 const char           *upnp_type)
{
        return g_hash_table_remove (factory->priv->proxy_type_hash, upnp_type);
465
}