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