2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2012 - 2013, Digium, Inc.
6 * Joshua Colp <jcolp@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Sorcery Data Access Layer API
23 * \author Joshua Colp <jcolp@digium.com>
27 <support_level>core</support_level>
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34 #include "asterisk/logger.h"
35 #include "asterisk/sorcery.h"
36 #include "asterisk/astobj2.h"
37 #include "asterisk/format.h"
38 #include "asterisk/format_cap.h"
39 #include "asterisk/strings.h"
40 #include "asterisk/config_options.h"
41 #include "asterisk/netsock2.h"
42 #include "asterisk/module.h"
43 #include "asterisk/taskprocessor.h"
44 #include "asterisk/threadpool.h"
45 #include "asterisk/json.h"
47 /* To prevent DEBUG_FD_LEAKS from interfering with things we undef open and close */
51 /*! \brief Number of buckets for wizards (should be prime for performance reasons) */
52 #define WIZARD_BUCKETS 7
54 /*! \brief Number of buckets for types (should be prime for performance reasons) */
55 #define TYPE_BUCKETS 53
57 /*! \brief Number of buckets for instances (should be prime for performance reasons) */
58 #define INSTANCE_BUCKETS 17
60 /*! \brief Number of buckets for object fields (should be prime for performance reasons) */
61 #define OBJECT_FIELD_BUCKETS 29
63 #define NOTIFY_GENERIC_OBSERVERS(container, type, callback, ...) ({ \
64 struct ao2_iterator i = ao2_iterator_init(container, 0); \
65 struct type *observer; \
66 ao2_rdlock(container); \
67 while ((observer = ao2_iterator_next(&i))) { \
68 if (observer->callbacks->callback) { \
69 observer->callbacks->callback(__VA_ARGS__); \
71 ao2_cleanup(observer); \
73 ao2_unlock(container); \
74 ao2_iterator_cleanup(&i); \
77 #define NOTIFY_GLOBAL_OBSERVERS(container, callback, ...) \
78 NOTIFY_GENERIC_OBSERVERS(container, sorcery_global_observer, callback, __VA_ARGS__)
80 #define NOTIFY_INSTANCE_OBSERVERS(container, callback, ...) \
81 NOTIFY_GENERIC_OBSERVERS(container, sorcery_instance_observer, callback, __VA_ARGS__)
83 #define NOTIFY_WIZARD_OBSERVERS(container, callback, ...) \
84 NOTIFY_GENERIC_OBSERVERS(container, sorcery_wizard_observer, callback, __VA_ARGS__)
86 /*! \brief Thread pool for observers */
87 static struct ast_threadpool *threadpool;
89 /*! \brief Structure for internal sorcery object information */
90 struct ast_sorcery_object {
91 /*! \brief Unique identifier of this object */
94 /*! \brief Type of object */
95 char type[MAX_OBJECT_TYPE];
97 /*! \brief Optional object destructor */
98 ao2_destructor_fn destructor;
100 /*! \brief Extended object fields */
101 struct ast_variable *extended;
104 /*! \brief Structure for registered object type */
105 struct ast_sorcery_object_type {
106 /*! \brief Unique name of the object type */
107 char name[MAX_OBJECT_TYPE];
109 /*! \brief Optional transformation callback */
110 sorcery_transform_handler transform;
112 /*! \brief Optional object set apply callback */
113 sorcery_apply_handler apply;
115 /*! \brief Optional object copy callback */
116 sorcery_copy_handler copy;
118 /*! \brief Optional object diff callback */
119 sorcery_diff_handler diff;
121 /*! \brief Wizard instances */
122 struct ao2_container *wizards;
124 /*! \brief Object fields */
125 struct ao2_container *fields;
127 /*! \brief Configuration framework general information */
128 struct aco_info *info;
130 /*! \brief Configuration framework file information */
131 struct aco_file *file;
133 /*! \brief Type details */
134 struct aco_type type;
136 /*! \brief Observers */
137 struct ao2_container *observers;
139 /*! \brief Serializer for observers */
140 struct ast_taskprocessor *serializer;
142 /*! \brief Specifies if object type is reloadable or not */
143 unsigned int reloadable:1;
146 /*! \brief Structure for registered object type observer */
147 struct ast_sorcery_object_type_observer {
148 /*! \brief Pointer to the observer implementation */
149 const struct ast_sorcery_observer *callbacks;
152 /*! \brief Structure used for observer invocations */
153 struct sorcery_observer_invocation {
154 /*! \brief Pointer to the object type */
155 struct ast_sorcery_object_type *object_type;
157 /*! \brief Pointer to the object */
161 /*! \brief Structure for registered object field */
162 struct ast_sorcery_object_field {
163 /*! \brief Name of the field */
164 char name[MAX_OBJECT_FIELD];
166 /*! \brief The compiled name regex if name is a regex */
169 /*! \brief Callback function for translation of a single value */
170 sorcery_field_handler handler;
172 /*! \brief Callback function for translation of multiple values */
173 sorcery_fields_handler multiple_handler;
175 /*! \brief Position of the field */
179 /*! \brief Structure for an internal wizard instance */
180 struct ast_sorcery_internal_wizard {
181 /*! \brief Wizard interface itself */
182 struct ast_sorcery_wizard callbacks;
184 /*! \brief Observers */
185 struct ao2_container *observers;
188 /*! \brief Structure for a wizard instance which operates on objects */
189 struct ast_sorcery_object_wizard {
190 /*! \brief Wizard interface itself */
191 struct ast_sorcery_internal_wizard *wizard;
193 /*! \brief Unique data for the wizard */
196 /*! \brief Wizard is acting as an object cache */
197 unsigned int caching:1;
200 /*! \brief Full structure for sorcery */
202 /*! \brief Container for known object types */
203 struct ao2_container *types;
205 /*! \brief Observers */
206 struct ao2_container *observers;
208 /*! \brief The name of the module owning this sorcery instance */
212 /*! \brief Structure for passing load/reload details */
213 struct sorcery_load_details {
214 /*! \brief Sorcery structure in use */
215 const struct ast_sorcery *sorcery;
217 /*! \brief Type of object being loaded */
220 /*! \brief Whether this is a reload or not */
221 unsigned int reload:1;
224 /*! \brief Registered sorcery wizards */
225 static struct ao2_container *wizards;
227 /* The following 3 observer wrappers must name their
228 * external observer 'callbacks' and it must be
229 * the first member of the structure. Common macros
230 * and container callbacks depend on it.
233 /*! \brief A global observer wrapper */
234 struct sorcery_global_observer {
235 const struct ast_sorcery_global_observer *callbacks;
238 /*! \brief An instance observer wrapper */
239 struct sorcery_instance_observer {
240 const struct ast_sorcery_instance_observer *callbacks;
243 /*! \brief A wizard observer wrapper */
244 struct sorcery_wizard_observer {
245 const struct ast_sorcery_wizard_observer *callbacks;
248 /*! \brief Registered global observers */
249 struct ao2_container *observers;
251 /*! \brief Registered sorcery instances */
252 static struct ao2_container *instances;
254 static int int_handler_fn(const void *obj, const intptr_t *args, char **buf)
256 int *field = (int *)(obj + args[0]);
257 return (ast_asprintf(buf, "%d", *field) < 0) ? -1 : 0;
260 static int uint_handler_fn(const void *obj, const intptr_t *args, char **buf)
262 unsigned int *field = (unsigned int *)(obj + args[0]);
263 return (ast_asprintf(buf, "%u", *field) < 0) ? -1 : 0;
266 static int double_handler_fn(const void *obj, const intptr_t *args, char **buf)
268 double *field = (double *)(obj + args[0]);
269 return (ast_asprintf(buf, "%f", *field) < 0) ? -1 : 0;
272 static int stringfield_handler_fn(const void *obj, const intptr_t *args, char **buf)
274 ast_string_field *field = (const char **)(obj + args[0]);
275 return !(*buf = ast_strdup(*field)) ? -1 : 0;
278 static int bool_handler_fn(const void *obj, const intptr_t *args, char **buf)
280 unsigned int *field = (unsigned int *)(obj + args[0]);
281 return !(*buf = ast_strdup(*field ? "true" : "false")) ? -1 : 0;
284 static int sockaddr_handler_fn(const void *obj, const intptr_t *args, char **buf)
286 struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + args[0]);
287 return !(*buf = ast_strdup(ast_sockaddr_stringify(field))) ? -1 : 0;
290 static int chararray_handler_fn(const void *obj, const intptr_t *args, char **buf)
292 char *field = (char *)(obj + args[0]);
293 return !(*buf = ast_strdup(field)) ? -1 : 0;
296 static int codec_handler_fn(const void *obj, const intptr_t *args, char **buf)
298 struct ast_str *codec_buf = ast_str_alloca(64);
299 struct ast_format_cap **cap = (struct ast_format_cap **)(obj + args[0]);
300 return !(*buf = ast_strdup(ast_format_cap_get_names(*cap, &codec_buf)));
303 static sorcery_field_handler sorcery_field_default_handler(enum aco_option_type type)
306 case OPT_BOOL_T: return bool_handler_fn;
307 case OPT_CHAR_ARRAY_T: return chararray_handler_fn;
308 case OPT_CODEC_T: return codec_handler_fn;
309 case OPT_DOUBLE_T: return double_handler_fn;
310 case OPT_INT_T: return int_handler_fn;
311 case OPT_SOCKADDR_T: return sockaddr_handler_fn;
312 case OPT_STRINGFIELD_T: return stringfield_handler_fn;
313 case OPT_UINT_T: return uint_handler_fn;
316 case OPT_CUSTOM_T: return NULL;
322 /*! \brief Hashing function for sorcery wizards */
323 static int sorcery_wizard_hash(const void *obj, const int flags)
325 const struct ast_sorcery_internal_wizard *object;
328 switch (flags & OBJ_SEARCH_MASK) {
332 case OBJ_SEARCH_OBJECT:
334 key = object->callbacks.name;
340 return ast_str_hash(key);
343 /*! \brief Comparator function for sorcery wizards */
344 static int sorcery_wizard_cmp(void *obj, void *arg, int flags)
346 const struct ast_sorcery_internal_wizard *object_left = obj;
347 const struct ast_sorcery_internal_wizard *object_right = arg;
348 const char *right_key = arg;
351 switch (flags & OBJ_SEARCH_MASK) {
352 case OBJ_SEARCH_OBJECT:
353 right_key = object_right->callbacks.name;
356 cmp = strcmp(object_left->callbacks.name, right_key);
358 case OBJ_SEARCH_PARTIAL_KEY:
359 cmp = strncmp(object_left->callbacks.name, right_key, strlen(right_key));
371 /*! \brief Hashing function for sorcery wizards */
372 static int object_type_field_hash(const void *obj, const int flags)
374 const struct ast_sorcery_object_field *object_field;
377 switch (flags & OBJ_SEARCH_MASK) {
381 case OBJ_SEARCH_OBJECT:
383 key = object_field->name;
389 return ast_str_hash(key);
392 static int object_type_field_cmp(void *obj, void *arg, int flags)
394 const struct ast_sorcery_object_field *field_left = obj;
395 const struct ast_sorcery_object_field *field_right = arg;
396 const char *right_key = arg;
399 switch (flags & OBJ_SEARCH_MASK) {
400 case OBJ_SEARCH_OBJECT:
401 right_key = field_right->name;
404 cmp = strcmp(field_left->name, right_key);
406 case OBJ_SEARCH_PARTIAL_KEY:
407 cmp = strncmp(field_left->name, right_key, strlen(right_key));
419 /*! \brief Cleanup function */
420 static void sorcery_exit(void)
422 ast_threadpool_shutdown(threadpool);
426 /*! \brief Cleanup function for graceful shutdowns */
427 static void sorcery_cleanup(void)
429 ao2_cleanup(wizards);
431 ao2_cleanup(observers);
433 ao2_cleanup(instances);
437 /*! \brief Compare function for sorcery instances */
438 static int sorcery_instance_cmp(void *obj, void *arg, int flags)
440 const struct ast_sorcery *object_left = obj;
441 const struct ast_sorcery *object_right = arg;
442 const char *right_key = arg;
445 switch (flags & OBJ_SEARCH_MASK) {
446 case OBJ_SEARCH_OBJECT:
447 right_key = object_right->module_name;
450 cmp = strcmp(object_left->module_name, right_key);
452 case OBJ_SEARCH_PARTIAL_KEY:
453 cmp = strncmp(object_left->module_name, right_key, strlen(right_key));
465 /*! \brief Hashing function for sorcery instances */
466 static int sorcery_instance_hash(const void *obj, const int flags)
468 const struct ast_sorcery *object;
471 switch (flags & OBJ_SEARCH_MASK) {
475 case OBJ_SEARCH_OBJECT:
477 key = object->module_name;
483 return ast_str_hash(key);
486 int ast_sorcery_init(void)
488 struct ast_threadpool_options options = {
489 .version = AST_THREADPOOL_OPTIONS_VERSION,
495 ast_assert(wizards == NULL);
497 if (!(threadpool = ast_threadpool_create("Sorcery", NULL, &options))) {
502 if (!(wizards = ao2_container_alloc(WIZARD_BUCKETS, sorcery_wizard_hash, sorcery_wizard_cmp))) {
503 ast_threadpool_shutdown(threadpool);
507 observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL);
514 instances = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, INSTANCE_BUCKETS,
515 sorcery_instance_hash, sorcery_instance_cmp);
522 ast_register_cleanup(sorcery_cleanup);
523 ast_register_atexit(sorcery_exit);
528 static void sorcery_internal_wizard_destructor(void *obj)
530 struct ast_sorcery_internal_wizard *wizard = obj;
532 ao2_cleanup(wizard->observers);
535 int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module)
537 struct ast_sorcery_internal_wizard *wizard;
540 ast_assert(!ast_strlen_zero(interface->name));
544 if ((wizard = ao2_find(wizards, interface->name, OBJ_KEY | OBJ_NOLOCK))) {
545 ast_log(LOG_WARNING, "Attempted to register sorcery wizard '%s' twice\n",
550 if (!(wizard = ao2_alloc(sizeof(*wizard), sorcery_internal_wizard_destructor))) {
554 wizard->callbacks = *interface;
555 wizard->callbacks.module = module;
557 wizard->observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL);
558 if (!wizard->observers) {
562 ao2_link_flags(wizards, wizard, OBJ_NOLOCK);
565 ast_verb(2, "Sorcery registered wizard '%s'\n", interface->name);
567 NOTIFY_GLOBAL_OBSERVERS(observers, wizard_registered,
568 interface->name, interface);
577 int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
579 struct ast_sorcery_internal_wizard *wizard =
580 interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL;
583 NOTIFY_GLOBAL_OBSERVERS(observers, wizard_unregistering, wizard->callbacks.name, &wizard->callbacks);
584 ao2_unlink(wizards, wizard);
586 ast_verb(2, "Sorcery unregistered wizard '%s'\n", interface->name);
593 /*! \brief Internal callback function for removing a generic observer */
594 static int sorcery_generic_observer_remove(void *obj, void *arg, int flags)
596 const struct sorcery_global_observer *observer = obj;
598 return (observer->callbacks == arg) ? CMP_MATCH | CMP_STOP : 0;
601 int ast_sorcery_global_observer_add(const struct ast_sorcery_global_observer *callbacks)
603 struct sorcery_global_observer *cb;
605 cb = ao2_alloc(sizeof(*cb), NULL);
610 cb->callbacks = callbacks;
611 ao2_link(observers, cb);
617 void ast_sorcery_global_observer_remove(
618 const struct ast_sorcery_global_observer *callbacks)
620 ao2_callback(observers, OBJ_NODATA | OBJ_UNLINK, sorcery_generic_observer_remove, (void *)callbacks);
623 int ast_sorcery_instance_observer_add(struct ast_sorcery *sorcery,
624 const struct ast_sorcery_instance_observer *callbacks)
626 struct sorcery_instance_observer *cb;
628 cb = ao2_alloc(sizeof(*cb), NULL);
633 cb->callbacks = callbacks;
634 ao2_link(sorcery->observers, cb);
640 void ast_sorcery_instance_observer_remove(struct ast_sorcery *sorcery,
641 const struct ast_sorcery_instance_observer *callbacks)
643 ao2_callback(sorcery->observers, OBJ_NODATA | OBJ_UNLINK, sorcery_generic_observer_remove, (void *)callbacks);
646 int ast_sorcery_wizard_observer_add(struct ast_sorcery_wizard *interface,
647 const struct ast_sorcery_wizard_observer *callbacks)
649 RAII_VAR(struct ast_sorcery_internal_wizard *, wizard,
650 interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL,
654 struct sorcery_wizard_observer *cb;
656 cb = ao2_alloc(sizeof(*cb), NULL);
661 cb->callbacks = callbacks;
662 ao2_link(wizard->observers, cb);
671 void ast_sorcery_wizard_observer_remove(struct ast_sorcery_wizard *interface,
672 const struct ast_sorcery_wizard_observer *callbacks)
674 RAII_VAR(struct ast_sorcery_internal_wizard *, wizard,
675 interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL,
679 ao2_callback(wizard->observers, OBJ_NODATA | OBJ_UNLINK, sorcery_generic_observer_remove, (void *)callbacks);
683 /*! \brief Destructor called when sorcery structure is destroyed */
684 static void sorcery_destructor(void *obj)
686 struct ast_sorcery *sorcery = obj;
688 if (sorcery->observers) {
689 NOTIFY_GLOBAL_OBSERVERS(observers, instance_destroying, sorcery->module_name, sorcery);
691 ao2_cleanup(sorcery->observers);
692 ao2_cleanup(sorcery->types);
695 /*! \brief Hashing function for sorcery types */
696 static int sorcery_type_hash(const void *obj, const int flags)
698 const struct ast_sorcery_object_type *object;
701 switch (flags & OBJ_SEARCH_MASK) {
705 case OBJ_SEARCH_OBJECT:
713 return ast_str_hash(key);
716 /*! \brief Comparator function for sorcery types */
717 static int sorcery_type_cmp(void *obj, void *arg, int flags)
719 const struct ast_sorcery_object_type *object_left = obj;
720 const struct ast_sorcery_object_type *object_right = arg;
721 const char *right_key = arg;
724 switch (flags & OBJ_SEARCH_MASK) {
725 case OBJ_SEARCH_OBJECT:
726 right_key = object_right->name;
729 cmp = strcmp(object_left->name, right_key);
731 case OBJ_SEARCH_PARTIAL_KEY:
732 cmp = strncmp(object_left->name, right_key, strlen(right_key));
744 struct ast_sorcery *__ast_sorcery_open(const char *module_name)
746 struct ast_sorcery *sorcery;
748 ast_assert(module_name != NULL);
750 ao2_wrlock(instances);
751 if ((sorcery = ao2_find(instances, module_name, OBJ_SEARCH_KEY | OBJ_NOLOCK))) {
755 if (!(sorcery = ao2_alloc(sizeof(*sorcery) + strlen(module_name) + 1, sorcery_destructor))) {
759 if (!(sorcery->types = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, TYPE_BUCKETS, sorcery_type_hash, sorcery_type_cmp))) {
760 ao2_ref(sorcery, -1);
765 if (!(sorcery->observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL))) {
766 ao2_ref(sorcery, -1);
771 strcpy(sorcery->module_name, module_name); /* Safe */
773 if (__ast_sorcery_apply_config(sorcery, module_name, module_name) == AST_SORCERY_APPLY_FAIL) {
774 ast_log(LOG_ERROR, "Error attempting to apply configuration %s to sorcery.\n", module_name);
775 ao2_cleanup(sorcery);
780 ao2_link_flags(instances, sorcery, OBJ_NOLOCK);
782 NOTIFY_GLOBAL_OBSERVERS(observers, instance_created, module_name, sorcery);
785 ao2_unlock(instances);
789 /*! \brief Search function for sorcery instances */
790 struct ast_sorcery *ast_sorcery_retrieve_by_module_name(const char *module_name)
792 return ao2_find(instances, module_name, OBJ_SEARCH_KEY);
795 /*! \brief Destructor function for object types */
796 static void sorcery_object_type_destructor(void *obj)
798 struct ast_sorcery_object_type *object_type = obj;
800 ao2_cleanup(object_type->wizards);
801 ao2_cleanup(object_type->fields);
802 ao2_cleanup(object_type->observers);
804 if (object_type->info) {
805 aco_info_destroy(object_type->info);
806 ast_free(object_type->info);
809 ast_free(object_type->file);
811 ast_taskprocessor_unreference(object_type->serializer);
814 /*! \brief Internal function which allocates an object type structure */
815 static struct ast_sorcery_object_type *sorcery_object_type_alloc(const char *type, const char *module)
817 struct ast_sorcery_object_type *object_type;
818 char uuid[AST_UUID_STR_LEN];
820 if (!(object_type = ao2_alloc(sizeof(*object_type), sorcery_object_type_destructor))) {
824 /* Order matters for object wizards */
825 if (!(object_type->wizards = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, sorcery_wizard_cmp))) {
826 ao2_ref(object_type, -1);
830 if (!(object_type->fields = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, OBJECT_FIELD_BUCKETS,
831 object_type_field_hash, object_type_field_cmp))) {
832 ao2_ref(object_type, -1);
836 if (!(object_type->observers = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, 1, NULL, NULL))) {
837 ao2_ref(object_type, -1);
841 if (!(object_type->info = ast_calloc(1, sizeof(*object_type->info) + 2 * sizeof(object_type->info->files[0])))) {
842 ao2_ref(object_type, -1);
846 if (!(object_type->file = ast_calloc(1, sizeof(*object_type->file) + 2 * sizeof(object_type->file->types[0])))) {
847 ao2_ref(object_type, -1);
851 if (!ast_uuid_generate_str(uuid, sizeof(uuid))) {
852 ao2_ref(object_type, -1);
856 if (!(object_type->serializer = ast_threadpool_serializer(uuid, threadpool))) {
857 ao2_ref(object_type, -1);
861 object_type->info->files[0] = object_type->file;
862 object_type->info->files[1] = NULL;
863 object_type->info->module = module;
865 ast_copy_string(object_type->name, type, sizeof(object_type->name));
870 /*! \brief Object wizard destructor */
871 static void sorcery_object_wizard_destructor(void *obj)
873 struct ast_sorcery_object_wizard *object_wizard = obj;
875 if (object_wizard->data) {
876 object_wizard->wizard->callbacks.close(object_wizard->data);
879 if (object_wizard->wizard) {
880 ast_module_unref(object_wizard->wizard->callbacks.module);
883 ao2_cleanup(object_wizard->wizard);
886 /*! \brief Internal function which creates an object type and adds a wizard mapping */
887 enum ast_sorcery_apply_result __ast_sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery,
888 const char *type, const char *module, const char *name, const char *data, unsigned int caching)
890 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
891 RAII_VAR(struct ast_sorcery_internal_wizard *, wizard, ao2_find(wizards, name, OBJ_KEY), ao2_cleanup);
892 RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, ao2_alloc(sizeof(*object_wizard), sorcery_object_wizard_destructor), ao2_cleanup);
896 ast_log(LOG_ERROR, "Wizard '%s' could not be applied to object type '%s' as it was not found\n",
898 return AST_SORCERY_APPLY_FAIL;
899 } else if (!object_wizard) {
900 return AST_SORCERY_APPLY_FAIL;
904 if (!(object_type = sorcery_object_type_alloc(type, module))) {
905 return AST_SORCERY_APPLY_FAIL;
911 struct ast_sorcery_wizard *found;
913 found = ao2_find(object_type->wizards, wizard, OBJ_SEARCH_OBJECT);
915 ast_debug(1, "Wizard %s already applied to object type %s\n",
916 wizard->callbacks.name, object_type->name);
918 return AST_SORCERY_APPLY_DUPLICATE;
922 if (wizard->callbacks.open && !(object_wizard->data = wizard->callbacks.open(data))) {
923 return AST_SORCERY_APPLY_FAIL;
926 ast_module_ref(wizard->callbacks.module);
928 object_wizard->wizard = ao2_bump(wizard);
929 object_wizard->caching = caching;
931 ao2_link(object_type->wizards, object_wizard);
934 ao2_link(sorcery->types, object_type);
937 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, wizard_mapped,
938 sorcery->module_name, sorcery, type, &wizard->callbacks, data, object_wizard->data);
940 return AST_SORCERY_APPLY_SUCCESS;
943 enum ast_sorcery_apply_result __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, const char *module)
945 struct ast_flags flags = { 0 };
946 struct ast_config *config = ast_config_load2("sorcery.conf", "sorcery", flags);
947 struct ast_variable *mapping;
948 int res = AST_SORCERY_APPLY_SUCCESS;
951 return AST_SORCERY_APPLY_NO_CONFIGURATION;
954 if (config == CONFIG_STATUS_FILEINVALID) {
955 return AST_SORCERY_APPLY_FAIL;
958 for (mapping = ast_variable_browse(config, name); mapping; mapping = mapping->next) {
959 RAII_VAR(char *, mapping_name, ast_strdup(mapping->name), ast_free);
960 RAII_VAR(char *, mapping_value, ast_strdup(mapping->value), ast_free);
961 char *options = mapping_name;
962 char *type = strsep(&options, "/");
963 char *data = mapping_value;
964 char *wizard = strsep(&data, ",");
965 unsigned int caching = 0;
967 /* If no object type or wizard exists just skip, nothing we can do */
968 if (ast_strlen_zero(type) || ast_strlen_zero(wizard)) {
972 /* If the wizard is configured as a cache treat it as such */
973 if (!ast_strlen_zero(options) && strstr(options, "cache")) {
977 /* Any error immediately causes us to stop */
978 if (__ast_sorcery_apply_wizard_mapping(sorcery, type, module, wizard, data, caching) == AST_SORCERY_APPLY_FAIL) {
979 res = AST_SORCERY_APPLY_FAIL;
984 ast_config_destroy(config);
989 enum ast_sorcery_apply_result __ast_sorcery_apply_default(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name, const char *data)
991 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
993 /* Defaults can not be added if any existing mapping exists */
995 return AST_SORCERY_APPLY_DEFAULT_UNNECESSARY;
998 return __ast_sorcery_apply_wizard_mapping(sorcery, type, module, name, data, 0);
1001 static int sorcery_extended_config_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1003 return ast_sorcery_object_set_extended(obj, var->name, var->value);
1006 static int sorcery_extended_fields_handler(const void *obj, struct ast_variable **fields)
1008 const struct ast_sorcery_object_details *details = obj;
1010 if (details->object->extended) {
1011 *fields = ast_variables_dup(details->object->extended);
1019 int __ast_sorcery_object_register(struct ast_sorcery *sorcery, const char *type, unsigned int hidden, unsigned int reloadable, aco_type_item_alloc alloc, sorcery_transform_handler transform, sorcery_apply_handler apply)
1021 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1023 if (!object_type || object_type->type.item_alloc) {
1027 object_type->type.name = object_type->name;
1028 object_type->type.type = ACO_ITEM;
1029 object_type->type.category = ".?";
1030 object_type->type.item_alloc = alloc;
1031 object_type->type.hidden = hidden;
1033 object_type->reloadable = reloadable;
1034 object_type->transform = transform;
1035 object_type->apply = apply;
1036 object_type->file->types[0] = &object_type->type;
1037 object_type->file->types[1] = NULL;
1039 if (aco_info_init(object_type->info)) {
1043 if (ast_sorcery_object_fields_register(sorcery, type, "^@", sorcery_extended_config_handler, sorcery_extended_fields_handler)) {
1047 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, object_type_registered,
1048 sorcery->module_name, sorcery, type);
1053 void ast_sorcery_object_set_copy_handler(struct ast_sorcery *sorcery, const char *type, sorcery_copy_handler copy)
1055 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1061 object_type->copy = copy;
1064 void ast_sorcery_object_set_diff_handler(struct ast_sorcery *sorcery, const char *type, sorcery_diff_handler diff)
1066 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1072 object_type->diff = diff;
1075 static void sorcery_object_field_destructor(void *obj)
1077 struct ast_sorcery_object_field *object_field = obj;
1079 if (object_field->name_regex) {
1080 regfree(object_field->name_regex);
1084 int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *type, const char *regex, aco_option_handler config_handler, sorcery_fields_handler sorcery_handler)
1086 #define MAX_REGEX_ERROR_LEN 128
1087 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1088 RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, ao2_cleanup);
1091 if (!object_type || !object_type->type.item_alloc || !config_handler
1092 || !(object_field = ao2_alloc(sizeof(*object_field), sorcery_object_field_destructor))) {
1096 ast_copy_string(object_field->name, regex, sizeof(object_field->name));
1097 object_field->multiple_handler = sorcery_handler;
1099 if (!(object_field->name_regex = ast_calloc(1, sizeof(regex_t)))) {
1103 if ((rc = regcomp(object_field->name_regex, regex, REG_EXTENDED | REG_NOSUB))) {
1104 char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
1105 regerror(rc, object_field->name_regex, regerr, MAX_REGEX_ERROR_LEN);
1106 ast_log(LOG_ERROR, "Regular expression '%s' failed to compile: %s\n", regex, regerr);
1110 ao2_link(object_type->fields, object_field);
1111 __aco_option_register(object_type->info, regex, ACO_REGEX, object_type->file->types, "", OPT_CUSTOM_T, config_handler, 0, 1, 0);
1116 int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char *type, const char *name, const char *default_val, enum aco_option_type opt_type,
1117 aco_option_handler config_handler, sorcery_field_handler sorcery_handler, sorcery_fields_handler multiple_handler, unsigned int flags, unsigned int no_doc, unsigned int alias, size_t argc, ...)
1119 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1120 RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, ao2_cleanup);
1124 if (!strcmp(type, "id") || !object_type || !object_type->type.item_alloc) {
1128 if (!sorcery_handler) {
1129 sorcery_handler = sorcery_field_default_handler(opt_type);
1132 if (!(object_field = ao2_alloc(sizeof(*object_field) + argc * sizeof(object_field->args[0]), NULL))) {
1136 ast_copy_string(object_field->name, name, sizeof(object_field->name));
1137 object_field->handler = sorcery_handler;
1138 object_field->multiple_handler = multiple_handler;
1140 va_start(args, argc);
1141 for (pos = 0; pos < argc; pos++) {
1142 object_field->args[pos] = va_arg(args, size_t);
1147 ao2_link(object_type->fields, object_field);
1150 /* TODO: Improve this hack */
1152 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc);
1153 } else if (argc == 1) {
1154 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
1155 object_field->args[0]);
1156 } else if (argc == 2) {
1157 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
1158 object_field->args[0], object_field->args[1]);
1159 } else if (argc == 3) {
1160 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
1161 object_field->args[0], object_field->args[1], object_field->args[2]);
1163 ast_assert(0); /* The hack... she does us no good for this */
1169 /*! \brief Retrieves whether or not the type is reloadable */
1170 static int sorcery_reloadable(const struct ast_sorcery *sorcery, const char *type)
1172 RAII_VAR(struct ast_sorcery_object_type *, object_type,
1173 ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1174 return object_type && object_type->reloadable;
1177 static int sorcery_wizard_load(void *obj, void *arg, int flags)
1179 struct ast_sorcery_object_wizard *wizard = obj;
1180 struct sorcery_load_details *details = arg;
1181 void (*load)(void *data, const struct ast_sorcery *sorcery, const char *type);
1183 load = !details->reload ? wizard->wizard->callbacks.load : wizard->wizard->callbacks.reload;
1186 NOTIFY_WIZARD_OBSERVERS(wizard->wizard->observers, wizard_loading,
1187 wizard->wizard->callbacks.name, &wizard->wizard->callbacks, details->type, details->reload);
1189 load(wizard->data, details->sorcery, details->type);
1191 NOTIFY_WIZARD_OBSERVERS(wizard->wizard->observers, wizard_loaded,
1192 wizard->wizard->callbacks.name, &wizard->wizard->callbacks, details->type, details->reload);
1198 /*! \brief Destructor for observer invocation */
1199 static void sorcery_observer_invocation_destroy(void *obj)
1201 struct sorcery_observer_invocation *invocation = obj;
1203 ao2_cleanup(invocation->object_type);
1204 ao2_cleanup(invocation->object);
1207 /*! \brief Allocator function for observer invocation */
1208 static struct sorcery_observer_invocation *sorcery_observer_invocation_alloc(struct ast_sorcery_object_type *object_type, void *object)
1210 struct sorcery_observer_invocation *invocation = ao2_alloc(sizeof(*invocation), sorcery_observer_invocation_destroy);
1216 ao2_ref(object_type, +1);
1217 invocation->object_type = object_type;
1220 ao2_ref(object, +1);
1221 invocation->object = object;
1227 /*! \brief Internal callback function which notifies an individual observer that an object type has been loaded */
1228 static int sorcery_observer_notify_loaded(void *obj, void *arg, int flags)
1230 const struct ast_sorcery_object_type_observer *observer = obj;
1232 if (observer->callbacks->loaded) {
1233 observer->callbacks->loaded(arg);
1239 /*! \brief Internal callback function which notifies observers that an object type has been loaded */
1240 static int sorcery_observers_notify_loaded(void *data)
1242 struct sorcery_observer_invocation *invocation = data;
1244 ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_loaded, invocation->object_type->name);
1245 ao2_cleanup(invocation);
1250 static int sorcery_object_load(void *obj, void *arg, int flags)
1252 struct ast_sorcery_object_type *type = obj;
1253 struct sorcery_load_details *details = arg;
1255 if (!type->type.item_alloc) {
1259 details->type = type->name;
1261 if (details->reload && !sorcery_reloadable(details->sorcery, details->type)) {
1262 ast_log(LOG_NOTICE, "Type '%s' is not reloadable, maintaining previous values\n",
1267 NOTIFY_INSTANCE_OBSERVERS(details->sorcery->observers, object_type_loading,
1268 details->sorcery->module_name, details->sorcery, type->name, details->reload);
1270 ao2_callback(type->wizards, OBJ_NODATA, sorcery_wizard_load, details);
1272 NOTIFY_INSTANCE_OBSERVERS(details->sorcery->observers, object_type_loaded,
1273 details->sorcery->module_name, details->sorcery, type->name, details->reload);
1275 if (ao2_container_count(type->observers)) {
1276 struct sorcery_observer_invocation *invocation;
1278 invocation = sorcery_observer_invocation_alloc(type, NULL);
1280 && ast_taskprocessor_push(type->serializer, sorcery_observers_notify_loaded,
1282 ao2_cleanup(invocation);
1289 void ast_sorcery_load(const struct ast_sorcery *sorcery)
1291 struct sorcery_load_details details = {
1296 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loading,
1297 sorcery->module_name, sorcery, 0);
1299 ao2_callback(sorcery->types, OBJ_NODATA, sorcery_object_load, &details);
1301 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loaded,
1302 sorcery->module_name, sorcery, 0);
1305 void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type)
1307 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1308 struct sorcery_load_details details = {
1317 sorcery_object_load(object_type, &details, 0);
1320 void ast_sorcery_reload(const struct ast_sorcery *sorcery)
1322 struct sorcery_load_details details = {
1327 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loading,
1328 sorcery->module_name, sorcery, 1);
1330 ao2_callback(sorcery->types, OBJ_NODATA, sorcery_object_load, &details);
1332 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loaded,
1333 sorcery->module_name, sorcery, 1);
1337 void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
1339 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1340 struct sorcery_load_details details = {
1349 sorcery_object_load(object_type, &details, 0);
1352 void ast_sorcery_ref(struct ast_sorcery *sorcery)
1354 ao2_ref(sorcery, +1);
1357 static struct ast_variable *get_single_field_as_var_list(const void *object, struct ast_sorcery_object_field *object_field)
1359 struct ast_variable *tmp = NULL;
1362 if (!object_field->handler) {
1366 if (!(object_field->handler(object, object_field->args, &buf))) {
1367 tmp = ast_variable_new(object_field->name, S_OR(buf, ""), "");
1374 static struct ast_variable *get_multiple_fields_as_var_list(const void *object, struct ast_sorcery_object_field *object_field)
1376 struct ast_variable *tmp = NULL;
1378 if (!object_field->multiple_handler) {
1382 if (object_field->multiple_handler(object, &tmp)) {
1383 ast_variables_destroy(tmp);
1390 struct ast_variable *ast_sorcery_objectset_create2(const struct ast_sorcery *sorcery,
1391 const void *object, enum ast_sorcery_field_handler_flags flags)
1393 const struct ast_sorcery_object_details *details = object;
1394 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1395 struct ao2_iterator i;
1396 struct ast_sorcery_object_field *object_field;
1397 struct ast_variable *head = NULL;
1398 struct ast_variable *tail = NULL;
1404 i = ao2_iterator_init(object_type->fields, 0);
1406 for (; (object_field = ao2_iterator_next(&i)); ao2_ref(object_field, -1)) {
1407 struct ast_variable *tmp;
1410 case AST_HANDLER_PREFER_LIST:
1411 if ((tmp = get_multiple_fields_as_var_list(object, object_field)) ||
1412 (tmp = get_single_field_as_var_list(object, object_field))) {
1416 case AST_HANDLER_PREFER_STRING:
1417 if ((tmp = get_single_field_as_var_list(object, object_field)) ||
1418 (tmp = get_multiple_fields_as_var_list(object, object_field))) {
1422 case AST_HANDLER_ONLY_LIST:
1423 if ((tmp = get_multiple_fields_as_var_list(object, object_field))) {
1427 case AST_HANDLER_ONLY_STRING:
1428 if ((tmp = get_single_field_as_var_list(object, object_field))) {
1436 tail = ast_variable_list_append_hint(&head, tail, tmp);
1439 ao2_iterator_destroy(&i);
1444 struct ast_json *ast_sorcery_objectset_json_create(const struct ast_sorcery *sorcery, const void *object)
1446 const struct ast_sorcery_object_details *details = object;
1447 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1448 struct ao2_iterator i;
1449 struct ast_sorcery_object_field *object_field;
1450 struct ast_json *json = ast_json_object_create();
1453 if (!object_type || !json) {
1457 i = ao2_iterator_init(object_type->fields, 0);
1459 for (; !res && (object_field = ao2_iterator_next(&i)); ao2_ref(object_field, -1)) {
1460 if (object_field->multiple_handler) {
1461 struct ast_variable *tmp = NULL;
1462 struct ast_variable *field;
1464 if ((res = object_field->multiple_handler(object, &tmp))) {
1465 ast_variables_destroy(tmp);
1466 ao2_ref(object_field, -1);
1470 for (field = tmp; field; field = field->next) {
1471 struct ast_json *value = ast_json_string_create(field->value);
1473 if (!value || ast_json_object_set(json, field->name, value)) {
1479 ast_variables_destroy(tmp);
1480 } else if (object_field->handler) {
1482 struct ast_json *value = NULL;
1484 if ((res = object_field->handler(object, object_field->args, &buf))
1485 || !(value = ast_json_string_create(buf))
1486 || ast_json_object_set(json, object_field->name, value)) {
1496 ao2_iterator_destroy(&i);
1498 /* If any error occurs we destroy the JSON object so a partial objectset is not returned */
1500 ast_json_unref(json);
1507 int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object, struct ast_variable *objectset)
1509 const struct ast_sorcery_object_details *details = object;
1510 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1511 RAII_VAR(struct ast_variable *, transformed, NULL, ast_variables_destroy);
1512 struct ast_variable *field;
1519 if (object_type->transform && (transformed = object_type->transform(objectset))) {
1520 field = transformed;
1525 for (; field; field = field->next) {
1526 if ((res = aco_process_var(&object_type->type, details->object->id, field, object))) {
1531 if (!res && object_type->apply) {
1532 res = object_type->apply(sorcery, object);
1538 int ast_sorcery_changeset_create(const struct ast_variable *original, const struct ast_variable *modified, struct ast_variable **changes)
1540 const struct ast_variable *field;
1545 /* Unless the ast_variable list changes when examined... it can't differ from itself */
1546 if (original == modified) {
1550 for (field = modified; field; field = field->next) {
1551 const char *old_value = ast_variable_find_in_list(original, field->name);
1553 if (!old_value || strcmp(old_value, field->value)) {
1554 struct ast_variable *tmp;
1556 if (!(tmp = ast_variable_new(field->name, field->value, ""))) {
1561 tmp->next = *changes;
1566 /* If an error occurred do not return a partial changeset */
1568 ast_variables_destroy(*changes);
1575 static void sorcery_object_destructor(void *object)
1577 struct ast_sorcery_object_details *details = object;
1579 if (details->object->destructor) {
1580 details->object->destructor(object);
1583 ast_variables_destroy(details->object->extended);
1584 ast_free(details->object->id);
1587 void *ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
1589 void *object = ao2_alloc_options(size + sizeof(struct ast_sorcery_object), sorcery_object_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
1590 struct ast_sorcery_object_details *details = object;
1596 details->object = object + size;
1597 details->object->destructor = destructor;
1602 void *ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
1604 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1605 struct ast_sorcery_object_details *details;
1607 if (!object_type || !object_type->type.item_alloc ||
1608 !(details = object_type->type.item_alloc(id))) {
1612 if (ast_strlen_zero(id)) {
1613 char uuid[AST_UUID_STR_LEN];
1615 ast_uuid_generate_str(uuid, sizeof(uuid));
1616 details->object->id = ast_strdup(uuid);
1618 details->object->id = ast_strdup(id);
1621 ast_copy_string(details->object->type, type, sizeof(details->object->type));
1623 if (aco_set_defaults(&object_type->type, id, details)) {
1624 ao2_ref(details, -1);
1631 void *ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
1633 const struct ast_sorcery_object_details *details = object;
1634 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1635 struct ast_sorcery_object_details *copy = ast_sorcery_alloc(sorcery, details->object->type, details->object->id);
1636 RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy);
1641 } else if (object_type->copy) {
1642 res = object_type->copy(object, copy);
1643 } else if ((objectset = ast_sorcery_objectset_create(sorcery, object))) {
1644 res = ast_sorcery_objectset_apply(sorcery, copy, objectset);
1646 /* No native copy available and could not create an objectset, this copy has failed */
1658 int ast_sorcery_diff(const struct ast_sorcery *sorcery, const void *original, const void *modified, struct ast_variable **changes)
1660 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, ast_sorcery_object_get_type(original), OBJ_KEY), ao2_cleanup);
1664 if (strcmp(ast_sorcery_object_get_type(original), ast_sorcery_object_get_type(modified))) {
1668 if (original == modified) {
1670 } else if (!object_type->diff) {
1671 RAII_VAR(struct ast_variable *, objectset1, NULL, ast_variables_destroy);
1672 RAII_VAR(struct ast_variable *, objectset2, NULL, ast_variables_destroy);
1674 objectset1 = ast_sorcery_objectset_create(sorcery, original);
1675 objectset2 = ast_sorcery_objectset_create(sorcery, modified);
1677 return ast_sorcery_changeset_create(objectset1, objectset2, changes);
1679 return object_type->diff(original, modified, changes);
1683 /*! \brief Structure used when calling create, update, or delete */
1684 struct sorcery_details {
1685 /*! \brief Pointer to the sorcery instance */
1686 const struct ast_sorcery *sorcery;
1687 /*! \brief Pointer to the object itself */
1691 /*! \brief Internal function used to create an object in caching wizards */
1692 static int sorcery_cache_create(void *obj, void *arg, int flags)
1694 const struct ast_sorcery_object_wizard *object_wizard = obj;
1695 const struct sorcery_details *details = arg;
1697 if (!object_wizard->caching || !object_wizard->wizard->callbacks.create) {
1701 object_wizard->wizard->callbacks.create(details->sorcery, object_wizard->data, details->obj);
1706 void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
1708 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1709 void *object = NULL;
1710 struct ao2_iterator i;
1711 struct ast_sorcery_object_wizard *wizard;
1712 unsigned int cached = 0;
1714 if (!object_type || ast_strlen_zero(id)) {
1718 i = ao2_iterator_init(object_type->wizards, 0);
1719 for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
1720 if (wizard->wizard->callbacks.retrieve_id &&
1721 !(object = wizard->wizard->callbacks.retrieve_id(sorcery, wizard->data, object_type->name, id))) {
1725 cached = wizard->caching;
1727 ao2_ref(wizard, -1);
1730 ao2_iterator_destroy(&i);
1732 if (!cached && object) {
1733 ao2_callback(object_type->wizards, 0, sorcery_cache_create, object);
1739 void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
1741 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1742 void *object = NULL;
1743 struct ao2_iterator i;
1744 struct ast_sorcery_object_wizard *wizard;
1745 unsigned int cached = 0;
1751 /* If returning multiple objects create a container to store them in */
1752 if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
1753 if (!(object = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
1758 /* Inquire with the available wizards for retrieval */
1759 i = ao2_iterator_init(object_type->wizards, 0);
1760 for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
1761 if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
1762 if (wizard->wizard->callbacks.retrieve_multiple) {
1763 wizard->wizard->callbacks.retrieve_multiple(sorcery, wizard->data, object_type->name, object, fields);
1765 } else if (fields && wizard->wizard->callbacks.retrieve_fields) {
1766 if (wizard->wizard->callbacks.retrieve_fields) {
1767 object = wizard->wizard->callbacks.retrieve_fields(sorcery, wizard->data, object_type->name, fields);
1771 if ((flags & AST_RETRIEVE_FLAG_MULTIPLE) || !object) {
1775 cached = wizard->caching;
1777 ao2_ref(wizard, -1);
1780 ao2_iterator_destroy(&i);
1782 /* If we are returning a single object and it came from a non-cache source create it in any caches */
1783 if (!(flags & AST_RETRIEVE_FLAG_MULTIPLE) && !cached && object) {
1784 ao2_callback(object_type->wizards, 0, sorcery_cache_create, object);
1790 struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex)
1792 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1793 struct ao2_container *objects;
1794 struct ao2_iterator i;
1795 struct ast_sorcery_object_wizard *wizard;
1797 if (!object_type || !(objects = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
1801 i = ao2_iterator_init(object_type->wizards, 0);
1802 for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
1803 if (!wizard->wizard->callbacks.retrieve_regex) {
1807 wizard->wizard->callbacks.retrieve_regex(sorcery, wizard->data, object_type->name, objects, regex);
1809 ao2_iterator_destroy(&i);
1814 /*! \brief Internal function which returns if the wizard has created the object */
1815 static int sorcery_wizard_create(void *obj, void *arg, int flags)
1817 const struct ast_sorcery_object_wizard *object_wizard = obj;
1818 const struct sorcery_details *details = arg;
1820 if (!object_wizard->wizard->callbacks.create) {
1822 ast_log(LOG_ERROR, "Sorcery wizard '%s' doesn't contain a 'create' virtual function.\n",
1823 object_wizard->wizard->callbacks.name);
1826 return (!object_wizard->caching && !object_wizard->wizard->callbacks.create(details->sorcery, object_wizard->data, details->obj)) ? CMP_MATCH | CMP_STOP : 0;
1829 /*! \brief Internal callback function which notifies an individual observer that an object has been created */
1830 static int sorcery_observer_notify_create(void *obj, void *arg, int flags)
1832 const struct ast_sorcery_object_type_observer *observer = obj;
1834 if (observer->callbacks->created) {
1835 observer->callbacks->created(arg);
1841 /*! \brief Internal callback function which notifies observers that an object has been created */
1842 static int sorcery_observers_notify_create(void *data)
1844 struct sorcery_observer_invocation *invocation = data;
1846 ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_create, invocation->object);
1847 ao2_cleanup(invocation);
1852 int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
1854 const struct ast_sorcery_object_details *details = object;
1855 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1856 RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
1857 struct sorcery_details sdetails = {
1866 if ((object_wizard = ao2_callback(object_type->wizards, 0, sorcery_wizard_create, &sdetails)) &&
1867 ao2_container_count(object_type->observers)) {
1868 struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
1870 if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_create, invocation)) {
1871 ao2_cleanup(invocation);
1875 return object_wizard ? 0 : -1;
1878 /*! \brief Internal callback function which notifies an individual observer that an object has been updated */
1879 static int sorcery_observer_notify_update(void *obj, void *arg, int flags)
1881 const struct ast_sorcery_object_type_observer *observer = obj;
1883 if (observer->callbacks->updated) {
1884 observer->callbacks->updated(arg);
1890 /*! \brief Internal callback function which notifies observers that an object has been updated */
1891 static int sorcery_observers_notify_update(void *data)
1893 struct sorcery_observer_invocation *invocation = data;
1895 ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_update, invocation->object);
1896 ao2_cleanup(invocation);
1901 /*! \brief Internal function which returns if a wizard has updated the object */
1902 static int sorcery_wizard_update(void *obj, void *arg, int flags)
1904 const struct ast_sorcery_object_wizard *object_wizard = obj;
1905 const struct sorcery_details *details = arg;
1907 return (object_wizard->wizard->callbacks.update && !object_wizard->wizard->callbacks.update(details->sorcery, object_wizard->data, details->obj) &&
1908 !object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0;
1911 int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
1913 const struct ast_sorcery_object_details *details = object;
1914 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1915 RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
1916 struct sorcery_details sdetails = {
1925 if ((object_wizard = ao2_callback(object_type->wizards, 0, sorcery_wizard_update, &sdetails)) &&
1926 ao2_container_count(object_type->observers)) {
1927 struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
1929 if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_update, invocation)) {
1930 ao2_cleanup(invocation);
1934 return object_wizard ? 0 : -1;
1937 /*! \brief Internal callback function which notifies an individual observer that an object has been deleted */
1938 static int sorcery_observer_notify_delete(void *obj, void *arg, int flags)
1940 const struct ast_sorcery_object_type_observer *observer = obj;
1942 if (observer->callbacks->deleted) {
1943 observer->callbacks->deleted(arg);
1949 /*! \brief Internal callback function which notifies observers that an object has been deleted */
1950 static int sorcery_observers_notify_delete(void *data)
1952 struct sorcery_observer_invocation *invocation = data;
1954 ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_delete, invocation->object);
1955 ao2_cleanup(invocation);
1960 /*! \brief Internal function which returns if a wizard has deleted the object */
1961 static int sorcery_wizard_delete(void *obj, void *arg, int flags)
1963 const struct ast_sorcery_object_wizard *object_wizard = obj;
1964 const struct sorcery_details *details = arg;
1966 return (object_wizard->wizard->callbacks.delete && !object_wizard->wizard->callbacks.delete(details->sorcery, object_wizard->data, details->obj) &&
1967 !object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0;
1970 int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
1972 const struct ast_sorcery_object_details *details = object;
1973 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1974 RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
1975 struct sorcery_details sdetails = {
1984 if ((object_wizard = ao2_callback(object_type->wizards, 0, sorcery_wizard_delete, &sdetails)) &&
1985 ao2_container_count(object_type->observers)) {
1986 struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
1988 if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_delete, invocation)) {
1989 ao2_cleanup(invocation);
1993 return object_wizard ? 0 : -1;
1996 void ast_sorcery_unref(struct ast_sorcery *sorcery)
1999 /* One ref for what we just released, the other for the instances container. */
2000 ao2_wrlock(instances);
2001 if (ao2_ref(sorcery, -1) == 2) {
2002 ao2_unlink_flags(instances, sorcery, OBJ_NOLOCK);
2004 ao2_unlock(instances);
2008 const char *ast_sorcery_object_get_id(const void *object)
2010 const struct ast_sorcery_object_details *details = object;
2011 return details->object->id;
2014 const char *ast_sorcery_object_get_type(const void *object)
2016 const struct ast_sorcery_object_details *details = object;
2017 return details->object->type;
2020 const char *ast_sorcery_object_get_extended(const void *object, const char *name)
2022 const struct ast_sorcery_object_details *details = object;
2023 struct ast_variable *field;
2025 for (field = details->object->extended; field; field = field->next) {
2026 if (!strcmp(field->name + 1, name)) {
2027 return field->value;
2034 int ast_sorcery_object_set_extended(const void *object, const char *name, const char *value)
2036 RAII_VAR(struct ast_variable *, field, NULL, ast_variables_destroy);
2037 struct ast_variable *extended = ast_variable_new(name, value, ""), *previous = NULL;
2038 const struct ast_sorcery_object_details *details = object;
2044 for (field = details->object->extended; field; previous = field, field = field->next) {
2045 if (!strcmp(field->name, name)) {
2047 previous->next = field->next;
2049 details->object->extended = field->next;
2056 extended->next = details->object->extended;
2057 details->object->extended = extended;
2062 int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
2064 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
2065 struct ast_sorcery_object_type_observer *observer;
2068 if (!object_type || !callbacks) {
2072 if (!(observer = ao2_alloc(sizeof(*observer), NULL))) {
2076 observer->callbacks = callbacks;
2078 if (!ao2_link(object_type->observers, observer)) {
2081 ao2_ref(observer, -1);
2086 /*! \brief Internal callback function for removing an observer */
2087 static int sorcery_observer_remove(void *obj, void *arg, int flags)
2089 const struct ast_sorcery_object_type_observer *observer = obj;
2091 return (observer->callbacks == arg) ? CMP_MATCH | CMP_STOP : 0;
2094 void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
2096 RAII_VAR(struct ast_sorcery_object_type *, object_type, NULL, ao2_cleanup);
2097 struct ast_sorcery_observer *cbs = (struct ast_sorcery_observer *) callbacks;/* Remove const for traversal. */
2102 object_type = ao2_find(sorcery->types, type, OBJ_KEY);
2107 ao2_callback(object_type->observers, OBJ_NODATA | OBJ_UNLINK,
2108 sorcery_observer_remove, cbs);
2111 int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
2113 const char *right_key = arg;
2116 switch (flags & OBJ_SEARCH_MASK) {
2117 case OBJ_SEARCH_OBJECT:
2118 right_key = ast_sorcery_object_get_id(arg);
2120 case OBJ_SEARCH_KEY:
2121 cmp = strcmp(ast_sorcery_object_get_id(obj), right_key);
2123 case OBJ_SEARCH_PARTIAL_KEY:
2124 cmp = strncmp(ast_sorcery_object_get_id(obj), right_key, strlen(right_key));
2133 int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
2135 const char *right_key = arg;
2138 switch (flags & OBJ_SEARCH_MASK) {
2139 case OBJ_SEARCH_OBJECT:
2140 right_key = ast_sorcery_object_get_id(arg);
2142 case OBJ_SEARCH_KEY:
2143 if (strcmp(ast_sorcery_object_get_id(obj), right_key) == 0) {
2144 cmp = CMP_MATCH | CMP_STOP;
2147 case OBJ_SEARCH_PARTIAL_KEY:
2148 if (strncmp(ast_sorcery_object_get_id(obj), right_key, strlen(right_key)) == 0) {
2159 int ast_sorcery_object_id_hash(const void *obj, int flags) {
2160 if (flags & OBJ_SEARCH_OBJECT) {
2161 return ast_str_hash(ast_sorcery_object_get_id(obj));
2162 } else if (flags & OBJ_SEARCH_KEY) {
2163 return ast_str_hash(obj);
2168 struct ast_sorcery_object_type *ast_sorcery_get_object_type(const struct ast_sorcery *sorcery,
2171 return ao2_find(sorcery->types, type, OBJ_SEARCH_KEY);
2174 static int is_registered_cb(void *obj, void *arg, int flags)
2176 struct ast_sorcery_object_field *object_field = obj;
2180 if (object_field->name_regex
2181 && !regexec(object_field->name_regex, name, 0, NULL, 0)) {
2182 rc = CMP_MATCH | CMP_STOP;
2188 int ast_sorcery_is_object_field_registered(const struct ast_sorcery_object_type *object_type,
2189 const char *field_name)
2191 struct ast_sorcery_object_field *object_field;
2194 ast_assert(object_type != NULL);
2196 object_field = ao2_find(object_type->fields, field_name, OBJ_SEARCH_KEY);
2198 if (!object_field) {
2199 object_field = ao2_callback(object_type->fields, 0, is_registered_cb, (char *)field_name);
2202 if (!object_field) {
2206 ao2_cleanup(object_field);