1 /* GSequencer - Advanced GTK Sequencer
2 * Copyright (C) 2005-2020 Joël Krähemann
3 *
4 * This file is part of GSequencer.
5 *
6 * GSequencer is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * GSequencer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with GSequencer. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <ags/server/ags_registry.h>
21
22 #include <ags/object/ags_application_context.h>
23 #include <ags/object/ags_connectable.h>
24
25 #include <ags/server/ags_service_provider.h>
26 #include <ags/server/ags_server.h>
27
28 #include <ags/i18n.h>
29
30 void ags_registry_class_init(AgsRegistryClass *registry);
31 void ags_registry_connectable_interface_init(AgsConnectableInterface *connectable);
32 void ags_registry_init(AgsRegistry *registry);
33 void ags_registry_set_property(GObject *gobject,
34 guint prop_id,
35 const GValue *value,
36 GParamSpec *param_spec);
37 void ags_registry_get_property(GObject *gobject,
38 guint prop_id,
39 GValue *value,
40 GParamSpec *param_spec);
41 void ags_registry_add_to_registry(AgsConnectable *connectable);
42 void ags_registry_remove_from_registry(AgsConnectable *connectable);
43 void ags_registry_connect(AgsConnectable *connectable);
44 void ags_registry_disconnect(AgsConnectable *connectable);
45 void ags_registry_dispose(GObject *gobject);
46 void ags_registry_finalize(GObject *gobject);
47
48 /**
49 * SECTION:ags_registry
50 * @short_description: remote control registry
51 * @title: AgsRegistry
52 * @section_id:
53 * @include: ags/server/ags_registry.h
54 *
55 * The #AgsRegistry is a registry where you are able to lookup objects.
56 */
57
58 enum{
59 PROP_0,
60 PROP_SERVER,
61 };
62
63 static gpointer ags_registry_parent_class = NULL;
64
65 GType
ags_registry_get_type()66 ags_registry_get_type()
67 {
68 static volatile gsize g_define_type_id__volatile = 0;
69
70 if(g_once_init_enter (&g_define_type_id__volatile)){
71 GType ags_type_registry = 0;
72
73 static const GTypeInfo ags_registry_info = {
74 sizeof (AgsRegistryClass),
75 NULL, /* base_init */
76 NULL, /* base_finalize */
77 (GClassInitFunc) ags_registry_class_init,
78 NULL, /* class_finalize */
79 NULL, /* class_data */
80 sizeof (AgsRegistry),
81 0, /* n_preallocs */
82 (GInstanceInitFunc) ags_registry_init,
83 };
84
85 static const GInterfaceInfo ags_connectable_interface_info = {
86 (GInterfaceInitFunc) ags_registry_connectable_interface_init,
87 NULL, /* interface_finalize */
88 NULL, /* interface_data */
89 };
90
91 ags_type_registry = g_type_register_static(G_TYPE_OBJECT,
92 "AgsRegistry",
93 &ags_registry_info,
94 0);
95
96 g_type_add_interface_static(ags_type_registry,
97 AGS_TYPE_CONNECTABLE,
98 &ags_connectable_interface_info);
99
100 g_once_init_leave(&g_define_type_id__volatile, ags_type_registry);
101 }
102
103 return g_define_type_id__volatile;
104 }
105
106 GType
ags_registry_flags_get_type()107 ags_registry_flags_get_type()
108 {
109 static volatile gsize g_flags_type_id__volatile;
110
111 if(g_once_init_enter (&g_flags_type_id__volatile)){
112 static const GFlagsValue values[] = {
113 { AGS_REGISTRY_ADDED_TO_REGISTRY, "AGS_REGISTRY_ADDED_TO_REGISTRY", "registry-added-to-registry" },
114 { AGS_REGISTRY_CONNECTED, "AGS_REGISTRY_CONNECTED", "registry-connected" },
115 { 0, NULL, NULL }
116 };
117
118 GType g_flags_type_id = g_flags_register_static(g_intern_static_string("AgsRegistryFlags"), values);
119
120 g_once_init_leave (&g_flags_type_id__volatile, g_flags_type_id);
121 }
122
123 return g_flags_type_id__volatile;
124 }
125
126 void
ags_registry_class_init(AgsRegistryClass * registry)127 ags_registry_class_init(AgsRegistryClass *registry)
128 {
129 GObjectClass *gobject;
130 GParamSpec *param_spec;
131
132 ags_registry_parent_class = g_type_class_peek_parent(registry);
133
134 /* GObjectClass */
135 gobject = (GObjectClass *) registry;
136
137 gobject->set_property = ags_registry_set_property;
138 gobject->get_property = ags_registry_get_property;
139
140 gobject->dispose = ags_registry_dispose;
141 gobject->finalize = ags_registry_finalize;
142
143 /* properties */
144 /**
145 * AgsRegistry:server:
146 *
147 * The assigned #AgsServer
148 *
149 * Since: 3.0.0
150 */
151 param_spec = g_param_spec_object("server",
152 i18n("assigned server"),
153 i18n("The assigned server"),
154 AGS_TYPE_SERVER,
155 G_PARAM_READABLE | G_PARAM_WRITABLE);
156 g_object_class_install_property(gobject,
157 PROP_SERVER,
158 param_spec);
159 }
160
161 void
ags_registry_connectable_interface_init(AgsConnectableInterface * connectable)162 ags_registry_connectable_interface_init(AgsConnectableInterface *connectable)
163 {
164 connectable->add_to_registry = ags_registry_add_to_registry;
165 connectable->remove_from_registry = ags_registry_remove_from_registry;
166 connectable->connect = ags_registry_connect;
167 connectable->disconnect = ags_registry_disconnect;
168 }
169
170 void
ags_registry_init(AgsRegistry * registry)171 ags_registry_init(AgsRegistry *registry)
172 {
173 AgsApplicationContext *application_context;
174
175 application_context = ags_application_context_get_instance();
176
177 registry->flags = 0;
178
179 g_rec_mutex_init(&(registry->obj_mutex));
180
181 registry->counter = 0;
182
183 registry->entry = NULL;
184 }
185
186 void
ags_registry_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)187 ags_registry_set_property(GObject *gobject,
188 guint prop_id,
189 const GValue *value,
190 GParamSpec *param_spec)
191 {
192 AgsRegistry *registry;
193
194 registry = AGS_REGISTRY(gobject);
195
196 switch(prop_id){
197 case PROP_SERVER:
198 {
199 AgsServer *server;
200
201 server = (AgsServer *) g_value_get_object(value);
202
203 if(registry->server == (GObject *) server){
204 return;
205 }
206
207 if(registry->server != NULL){
208 g_object_unref(G_OBJECT(registry->server));
209 }
210
211 if(server != NULL){
212 g_object_ref(G_OBJECT(server));
213 }
214
215 registry->server = server;
216 }
217 break;
218 default:
219 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
220 break;
221 }
222 }
223
224 void
ags_registry_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)225 ags_registry_get_property(GObject *gobject,
226 guint prop_id,
227 GValue *value,
228 GParamSpec *param_spec)
229 {
230 AgsRegistry *registry;
231
232 registry = AGS_REGISTRY(gobject);
233
234 switch(prop_id){
235 case PROP_SERVER:
236 {
237 g_value_set_object(value, registry->server);
238 }
239 break;
240 default:
241 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
242 break;
243 }
244 }
245
246 void
ags_registry_add_to_registry(AgsConnectable * connectable)247 ags_registry_add_to_registry(AgsConnectable *connectable)
248 {
249 AgsRegistry *registry;
250
251 registry = AGS_REGISTRY(connectable);
252
253 //TODO:JK: implement me
254 }
255
256 void
ags_registry_remove_from_registry(AgsConnectable * connectable)257 ags_registry_remove_from_registry(AgsConnectable *connectable)
258 {
259 //TODO:JK: implement me
260 }
261
262 void
ags_registry_connect(AgsConnectable * connectable)263 ags_registry_connect(AgsConnectable *connectable)
264 {
265 /* empty */
266 }
267
268 void
ags_registry_disconnect(AgsConnectable * connectable)269 ags_registry_disconnect(AgsConnectable *connectable)
270 {
271 /* empty */
272 }
273
274 void
ags_registry_dispose(GObject * gobject)275 ags_registry_dispose(GObject *gobject)
276 {
277 AgsRegistry *registry;
278
279 registry = AGS_REGISTRY(gobject);
280
281 if(registry->server != NULL){
282 g_object_unref(registry->server);
283
284 registry->server = NULL;
285 }
286
287 g_list_free_full(registry->entry,
288 (GDestroyNotify) ags_registry_entry_free);
289
290 registry->entry = NULL;
291
292 /* call parent */
293 G_OBJECT_CLASS(ags_registry_parent_class)->dispose(gobject);
294 }
295
296 void
ags_registry_finalize(GObject * gobject)297 ags_registry_finalize(GObject *gobject)
298 {
299 AgsRegistry *registry;
300
301 registry = AGS_REGISTRY(gobject);
302
303 if(registry->server != NULL){
304 g_object_unref(registry->server);
305 }
306
307 g_list_free_full(registry->entry,
308 (GDestroyNotify) ags_registry_entry_free);
309
310 /* call parent */
311 G_OBJECT_CLASS(ags_registry_parent_class)->finalize(gobject);
312 }
313
314 /**
315 * ags_registry_entry_alloc:
316 *
317 * Allocated #AgsRegistryEntry-struct.
318 *
319 * Returns: the newly allocated #AgsRegistryEntry-struct
320 *
321 * Since: 3.0.0
322 */
323 AgsRegistryEntry*
ags_registry_entry_alloc()324 ags_registry_entry_alloc()
325 {
326 AgsRegistryEntry *registry_entry;
327
328 registry_entry = (AgsRegistryEntry *) malloc(sizeof(AgsRegistryEntry));
329
330 registry_entry->id = NULL;
331
332 registry_entry->entry = g_new0(GValue,
333 1);
334 g_value_init(registry_entry->entry,
335 G_TYPE_OBJECT);
336
337 return(registry_entry);
338 }
339
340 /**
341 * ags_registry_entry_free:
342 * @registry_entry: the #AgsRegistryEntry-struct
343 *
344 * Free @registry_entry
345 *
346 * Since: 3.0.0
347 */
348 void
ags_registry_entry_free(AgsRegistryEntry * registry_entry)349 ags_registry_entry_free(AgsRegistryEntry *registry_entry)
350 {
351 GObject *gobject;
352
353 gobject = g_value_get_object(&(registry_entry->entry));
354
355 if(gobject != NULL){
356 g_object_unref(gobject);
357 }
358
359 g_value_unset(registry_entry->entry);
360 g_free(registry_entry->entry);
361
362 free(registry_entry);
363 }
364
365 /**
366 * ags_registry_add_entry:
367 * @registry: the #AgsRegistry
368 * @registry_entry: the #AgsRegistryEntry-struct to add
369 *
370 * Add @registry_entry to @registry.
371 *
372 * Since: 3.0.0
373 */
374 void
ags_registry_add_entry(AgsRegistry * registry,AgsRegistryEntry * registry_entry)375 ags_registry_add_entry(AgsRegistry *registry,
376 AgsRegistryEntry *registry_entry)
377 {
378 GRecMutex *registry_mutex;
379
380 if(!AGS_IS_REGISTRY(registry) ||
381 registry_entry == NULL){
382 return;
383 }
384
385 registry_mutex = AGS_REGISTRY_GET_OBJ_MUTEX(registry);
386
387 g_rec_mutex_lock(registry_mutex);
388
389 registry->entry = g_list_prepend(registry->entry,
390 registry_entry);
391
392 g_rec_mutex_unlock(registry_mutex);
393 }
394
395 /**
396 * ags_registry_find_entry:
397 * @registry: the #AgsRegistry
398 * @id: the #AgsUUID to find
399 *
400 * Find @id as #AgsRegistryEntry-struct in @registry.
401 *
402 * Since: 3.0.0
403 */
404 AgsRegistryEntry*
ags_registry_find_entry(AgsRegistry * registry,AgsUUID * id)405 ags_registry_find_entry(AgsRegistry *registry,
406 AgsUUID *id)
407 {
408 GList *current;
409 AgsRegistryEntry *entry;
410
411 GRecMutex *registry_mutex;
412
413 if(!AGS_IS_REGISTRY(registry)){
414 return(NULL);
415 }
416
417 registry_mutex = AGS_REGISTRY_GET_OBJ_MUTEX(registry);
418
419 g_rec_mutex_lock(registry_mutex);
420
421 current = registry->entry;
422
423 while(current != NULL){
424 entry = (AgsRegistryEntry *) current->data;
425
426 if(!ags_uuid_compare(entry->id,
427 id)){
428 g_rec_mutex_unlock(registry_mutex);
429
430 return(entry);
431 }
432
433 current = current->next;
434 }
435
436 g_rec_mutex_unlock(registry_mutex);
437
438 return(NULL);
439 }
440
441 #ifdef AGS_WITH_XMLRPC_C
442 xmlrpc_value*
ags_registry_entry_bulk(xmlrpc_env * env,xmlrpc_value * param_array,void * server_info)443 ags_registry_entry_bulk(xmlrpc_env *env,
444 xmlrpc_value *param_array,
445 void *server_info)
446 {
447 AgsServer *server;
448 AgsRegistry *registry;
449 AgsRegistryEntry *entry;
450
451 AgsApplicationContext *application_context;
452
453 GList *current;
454
455 xmlrpc_value *bulk;
456 xmlrpc_value *item;
457
458 GRecMutex *registry_mutex;
459
460 server = ags_server_lookup(server_info);
461
462 application_context = ags_application_context_get_instance();
463
464 registry = ags_service_provider_get_registry(AGS_SERVICE_PROVIDER(application_context));
465
466 registry_mutex = AGS_REGISTRY_GET_OBJ_MUTEX(registry);
467
468 bulk = xmlrpc_array_new(env);
469
470 g_rec_mutex_lock(registry_mutex);
471
472 current = registry->entry;
473
474 while(current != NULL){
475 entry = (AgsRegistryEntry *) current->data;
476 item = xmlrpc_string_new(env, entry->id);
477
478 xmlrpc_array_append_item(env, bulk, item);
479
480 current = current->next;
481 }
482
483 g_rec_mutex_unlock(registry_mutex);
484
485 return(bulk);
486 }
487 #endif /* AGS_WITH_XMLRPC_C */
488
489 AgsRegistry*
ags_registry_new()490 ags_registry_new()
491 {
492 AgsRegistry *registry;
493
494 registry = (AgsRegistry *) g_object_new(AGS_TYPE_REGISTRY,
495 NULL);
496
497 return(registry);
498 }
499