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_REGISTER_FILE()
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"
46 #include "asterisk/vector.h"
48 /* To prevent DEBUG_FD_LEAKS from interfering with things we undef open and close */
52 /*! \brief Number of buckets for wizards (should be prime for performance reasons) */
53 #define WIZARD_BUCKETS 7
55 /*! \brief Number of buckets for types (should be prime for performance reasons) */
56 #define TYPE_BUCKETS 53
58 /*! \brief Number of buckets for instances (should be prime for performance reasons) */
59 #define INSTANCE_BUCKETS 17
61 /*! \brief Number of buckets for object fields (should be prime for performance reasons) */
62 #define OBJECT_FIELD_BUCKETS 29
64 #define NOTIFY_GENERIC_OBSERVERS(container, type, callback, ...) ({ \
65 struct ao2_iterator i = ao2_iterator_init(container, 0); \
66 struct type *observer; \
67 ao2_rdlock(container); \
68 while ((observer = ao2_iterator_next(&i))) { \
69 if (observer->callbacks->callback) { \
70 observer->callbacks->callback(__VA_ARGS__); \
72 ao2_cleanup(observer); \
74 ao2_unlock(container); \
75 ao2_iterator_cleanup(&i); \
78 #define NOTIFY_GLOBAL_OBSERVERS(container, callback, ...) \
79 NOTIFY_GENERIC_OBSERVERS(container, sorcery_global_observer, callback, __VA_ARGS__)
81 #define NOTIFY_INSTANCE_OBSERVERS(container, callback, ...) \
82 NOTIFY_GENERIC_OBSERVERS(container, sorcery_instance_observer, callback, __VA_ARGS__)
84 #define NOTIFY_WIZARD_OBSERVERS(container, callback, ...) \
85 NOTIFY_GENERIC_OBSERVERS(container, sorcery_wizard_observer, callback, __VA_ARGS__)
87 /*! \brief Thread pool for observers */
88 static struct ast_threadpool *threadpool;
90 /*! \brief Structure for an internal wizard instance */
91 struct ast_sorcery_internal_wizard {
93 * \brief Wizard interface itself
94 * \warning Callbacks must always be declared first in this structure
95 * so an ao2_ref on &callbacks will adjust the ref count on
98 struct ast_sorcery_wizard callbacks;
100 /*! \brief Observers */
101 struct ao2_container *observers;
104 /*! \brief Structure for a wizard instance which operates on objects */
105 struct ast_sorcery_object_wizard {
106 /*! \brief Wizard interface itself */
107 struct ast_sorcery_internal_wizard *wizard;
109 /*! \brief Unique data for the wizard */
112 /*! \brief Wizard is acting as an object cache */
113 unsigned int caching:1;
116 /*! \brief Interface for a sorcery object type wizards */
117 AST_VECTOR_RW(ast_sorcery_object_wizards, struct ast_sorcery_object_wizard *);
119 /*! \brief Structure for internal sorcery object information */
120 struct ast_sorcery_object {
121 /*! \brief Unique identifier of this object */
124 /*! \brief Type of object */
125 char type[MAX_OBJECT_TYPE];
127 /*! \brief Optional object destructor */
128 ao2_destructor_fn destructor;
130 /*! \brief Extended object fields */
131 struct ast_variable *extended;
134 /*! \brief Structure for registered object type */
135 struct ast_sorcery_object_type {
136 /*! \brief Unique name of the object type */
137 char name[MAX_OBJECT_TYPE];
139 /*! \brief Optional transformation callback */
140 sorcery_transform_handler transform;
142 /*! \brief Optional object set apply callback */
143 sorcery_apply_handler apply;
145 /*! \brief Optional object copy callback */
146 sorcery_copy_handler copy;
148 /*! \brief Optional object diff callback */
149 sorcery_diff_handler diff;
151 /*! \brief Wizard instances */
152 struct ast_sorcery_object_wizards wizards;
154 /*! \brief Object fields */
155 struct ao2_container *fields;
157 /*! \brief Configuration framework general information */
158 struct aco_info *info;
160 /*! \brief Configuration framework file information */
161 struct aco_file *file;
163 /*! \brief Type details */
164 struct aco_type type;
166 /*! \brief Observers */
167 struct ao2_container *observers;
169 /*! \brief Serializer for observers */
170 struct ast_taskprocessor *serializer;
172 /*! \brief Specifies if object type is reloadable or not */
173 unsigned int reloadable:1;
176 /*! \brief Structure for registered object type observer */
177 struct ast_sorcery_object_type_observer {
178 /*! \brief Pointer to the observer implementation */
179 const struct ast_sorcery_observer *callbacks;
182 /*! \brief Structure used for observer invocations */
183 struct sorcery_observer_invocation {
184 /*! \brief Pointer to the object type */
185 struct ast_sorcery_object_type *object_type;
187 /*! \brief Pointer to the object */
191 /*! \brief Structure for registered object field */
192 struct ast_sorcery_object_field {
193 /*! \brief Name of the field */
194 char name[MAX_OBJECT_FIELD];
196 /*! \brief The compiled name regex if name is a regex */
199 /*! \brief Callback function for translation of a single value */
200 sorcery_field_handler handler;
202 /*! \brief Callback function for translation of multiple values */
203 sorcery_fields_handler multiple_handler;
205 /*! \brief Position of the field */
209 /*! \brief Full structure for sorcery */
211 /*! \brief Container for known object types */
212 struct ao2_container *types;
214 /*! \brief Observers */
215 struct ao2_container *observers;
217 /*! \brief The name of the module owning this sorcery instance */
221 /*! \brief Structure for passing load/reload details */
222 struct sorcery_load_details {
223 /*! \brief Sorcery structure in use */
224 const struct ast_sorcery *sorcery;
226 /*! \brief Type of object being loaded */
229 /*! \brief Whether this is a reload or not */
230 unsigned int reload:1;
233 /*! \brief Registered sorcery wizards */
234 static struct ao2_container *wizards;
236 /* The following 3 observer wrappers must name their
237 * external observer 'callbacks' and it must be
238 * the first member of the structure. Common macros
239 * and container callbacks depend on it.
242 /*! \brief A global observer wrapper */
243 struct sorcery_global_observer {
244 const struct ast_sorcery_global_observer *callbacks;
247 /*! \brief An instance observer wrapper */
248 struct sorcery_instance_observer {
249 const struct ast_sorcery_instance_observer *callbacks;
252 /*! \brief A wizard observer wrapper */
253 struct sorcery_wizard_observer {
254 const struct ast_sorcery_wizard_observer *callbacks;
257 /*! \brief Registered global observers */
258 struct ao2_container *observers;
260 /*! \brief Registered sorcery instances */
261 static struct ao2_container *instances;
263 static int int_handler_fn(const void *obj, const intptr_t *args, char **buf)
265 int *field = (int *)(obj + args[0]);
266 return (ast_asprintf(buf, "%d", *field) < 0) ? -1 : 0;
269 static int uint_handler_fn(const void *obj, const intptr_t *args, char **buf)
271 unsigned int *field = (unsigned int *)(obj + args[0]);
272 return (ast_asprintf(buf, "%u", *field) < 0) ? -1 : 0;
275 static int double_handler_fn(const void *obj, const intptr_t *args, char **buf)
277 double *field = (double *)(obj + args[0]);
278 return (ast_asprintf(buf, "%f", *field) < 0) ? -1 : 0;
281 static int stringfield_handler_fn(const void *obj, const intptr_t *args, char **buf)
283 ast_string_field *field = (const char **)(obj + args[0]);
284 return !(*buf = ast_strdup(*field)) ? -1 : 0;
287 static int bool_handler_fn(const void *obj, const intptr_t *args, char **buf)
289 unsigned int *field = (unsigned int *)(obj + args[0]);
290 return !(*buf = ast_strdup(*field ? "true" : "false")) ? -1 : 0;
293 static int sockaddr_handler_fn(const void *obj, const intptr_t *args, char **buf)
295 struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + args[0]);
296 return !(*buf = ast_strdup(ast_sockaddr_stringify(field))) ? -1 : 0;
299 static int chararray_handler_fn(const void *obj, const intptr_t *args, char **buf)
301 char *field = (char *)(obj + args[0]);
302 return !(*buf = ast_strdup(field)) ? -1 : 0;
305 static int codec_handler_fn(const void *obj, const intptr_t *args, char **buf)
307 struct ast_str *codec_buf = ast_str_alloca(64);
308 struct ast_format_cap **cap = (struct ast_format_cap **)(obj + args[0]);
309 return !(*buf = ast_strdup(ast_format_cap_get_names(*cap, &codec_buf)));
312 static sorcery_field_handler sorcery_field_default_handler(enum aco_option_type type)
315 case OPT_BOOL_T: return bool_handler_fn;
316 case OPT_CHAR_ARRAY_T: return chararray_handler_fn;
317 case OPT_CODEC_T: return codec_handler_fn;
318 case OPT_DOUBLE_T: return double_handler_fn;
319 case OPT_INT_T: return int_handler_fn;
320 case OPT_SOCKADDR_T: return sockaddr_handler_fn;
321 case OPT_STRINGFIELD_T: return stringfield_handler_fn;
322 case OPT_UINT_T: return uint_handler_fn;
325 case OPT_CUSTOM_T: return NULL;
331 /*! \brief Hashing function for sorcery wizards */
332 static int sorcery_wizard_hash(const void *obj, const int flags)
334 const struct ast_sorcery_internal_wizard *object;
337 switch (flags & OBJ_SEARCH_MASK) {
341 case OBJ_SEARCH_OBJECT:
343 key = object->callbacks.name;
349 return ast_str_hash(key);
352 /*! \brief Comparator function for sorcery wizards */
353 static int sorcery_wizard_cmp(void *obj, void *arg, int flags)
355 const struct ast_sorcery_internal_wizard *object_left = obj;
356 const struct ast_sorcery_internal_wizard *object_right = arg;
357 const char *right_key = arg;
360 switch (flags & OBJ_SEARCH_MASK) {
361 case OBJ_SEARCH_OBJECT:
362 right_key = object_right->callbacks.name;
365 cmp = strcmp(object_left->callbacks.name, right_key);
367 case OBJ_SEARCH_PARTIAL_KEY:
368 cmp = strncmp(object_left->callbacks.name, right_key, strlen(right_key));
380 /*! \brief Hashing function for sorcery wizards */
381 static int object_type_field_hash(const void *obj, const int flags)
383 const struct ast_sorcery_object_field *object_field;
386 switch (flags & OBJ_SEARCH_MASK) {
390 case OBJ_SEARCH_OBJECT:
392 key = object_field->name;
398 return ast_str_hash(key);
401 static int object_type_field_cmp(void *obj, void *arg, int flags)
403 const struct ast_sorcery_object_field *field_left = obj;
404 const struct ast_sorcery_object_field *field_right = arg;
405 const char *right_key = arg;
408 switch (flags & OBJ_SEARCH_MASK) {
409 case OBJ_SEARCH_OBJECT:
410 right_key = field_right->name;
413 cmp = strcmp(field_left->name, right_key);
415 case OBJ_SEARCH_PARTIAL_KEY:
416 cmp = strncmp(field_left->name, right_key, strlen(right_key));
428 /*! \brief Cleanup function for graceful shutdowns */
429 static void sorcery_cleanup(void)
431 ast_threadpool_shutdown(threadpool);
433 ao2_cleanup(wizards);
435 ao2_cleanup(observers);
437 ao2_cleanup(instances);
441 /*! \brief Compare function for sorcery instances */
442 static int sorcery_instance_cmp(void *obj, void *arg, int flags)
444 const struct ast_sorcery *object_left = obj;
445 const struct ast_sorcery *object_right = arg;
446 const char *right_key = arg;
449 switch (flags & OBJ_SEARCH_MASK) {
450 case OBJ_SEARCH_OBJECT:
451 right_key = object_right->module_name;
454 cmp = strcmp(object_left->module_name, right_key);
456 case OBJ_SEARCH_PARTIAL_KEY:
457 cmp = strncmp(object_left->module_name, right_key, strlen(right_key));
469 /*! \brief Hashing function for sorcery instances */
470 static int sorcery_instance_hash(const void *obj, const int flags)
472 const struct ast_sorcery *object;
475 switch (flags & OBJ_SEARCH_MASK) {
479 case OBJ_SEARCH_OBJECT:
481 key = object->module_name;
487 return ast_str_hash(key);
490 int ast_sorcery_init(void)
492 struct ast_threadpool_options options = {
493 .version = AST_THREADPOOL_OPTIONS_VERSION,
499 ast_assert(wizards == NULL);
501 if (!(threadpool = ast_threadpool_create("Sorcery", NULL, &options))) {
506 if (!(wizards = ao2_container_alloc(WIZARD_BUCKETS, sorcery_wizard_hash, sorcery_wizard_cmp))) {
507 ast_threadpool_shutdown(threadpool);
511 observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL);
517 instances = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, INSTANCE_BUCKETS,
518 sorcery_instance_hash, sorcery_instance_cmp);
524 ast_register_cleanup(sorcery_cleanup);
529 static void sorcery_internal_wizard_destructor(void *obj)
531 struct ast_sorcery_internal_wizard *wizard = obj;
533 ao2_cleanup(wizard->observers);
536 int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module)
538 struct ast_sorcery_internal_wizard *wizard;
541 ast_assert(!ast_strlen_zero(interface->name));
545 if ((wizard = ao2_find(wizards, interface->name, OBJ_KEY | OBJ_NOLOCK))) {
546 ast_log(LOG_WARNING, "Attempted to register sorcery wizard '%s' twice\n",
551 if (!(wizard = ao2_alloc(sizeof(*wizard), sorcery_internal_wizard_destructor))) {
555 wizard->callbacks = *interface;
556 wizard->callbacks.module = module;
558 wizard->observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL);
559 if (!wizard->observers) {
563 ao2_link_flags(wizards, wizard, OBJ_NOLOCK);
566 ast_verb(2, "Sorcery registered wizard '%s'\n", interface->name);
568 NOTIFY_GLOBAL_OBSERVERS(observers, wizard_registered,
569 interface->name, interface);
578 int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
580 struct ast_sorcery_internal_wizard *wizard =
581 interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL;
584 NOTIFY_GLOBAL_OBSERVERS(observers, wizard_unregistering, wizard->callbacks.name, &wizard->callbacks);
585 ao2_unlink(wizards, wizard);
587 ast_verb(2, "Sorcery unregistered wizard '%s'\n", interface->name);
594 /*! \brief Internal callback function for removing a generic observer */
595 static int sorcery_generic_observer_remove(void *obj, void *arg, int flags)
597 const struct sorcery_global_observer *observer = obj;
599 return (observer->callbacks == arg) ? CMP_MATCH | CMP_STOP : 0;
602 int ast_sorcery_global_observer_add(const struct ast_sorcery_global_observer *callbacks)
604 struct sorcery_global_observer *cb;
606 cb = ao2_alloc(sizeof(*cb), NULL);
611 cb->callbacks = callbacks;
612 ao2_link(observers, cb);
618 void ast_sorcery_global_observer_remove(
619 const struct ast_sorcery_global_observer *callbacks)
621 ao2_callback(observers, OBJ_NODATA | OBJ_UNLINK, sorcery_generic_observer_remove, (void *)callbacks);
624 int ast_sorcery_instance_observer_add(struct ast_sorcery *sorcery,
625 const struct ast_sorcery_instance_observer *callbacks)
627 struct sorcery_instance_observer *cb;
629 cb = ao2_alloc(sizeof(*cb), NULL);
634 cb->callbacks = callbacks;
635 ao2_link(sorcery->observers, cb);
641 void ast_sorcery_instance_observer_remove(struct ast_sorcery *sorcery,
642 const struct ast_sorcery_instance_observer *callbacks)
644 ao2_callback(sorcery->observers, OBJ_NODATA | OBJ_UNLINK, sorcery_generic_observer_remove, (void *)callbacks);
647 int ast_sorcery_wizard_observer_add(struct ast_sorcery_wizard *interface,
648 const struct ast_sorcery_wizard_observer *callbacks)
650 RAII_VAR(struct ast_sorcery_internal_wizard *, wizard,
651 interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL,
655 struct sorcery_wizard_observer *cb;
657 cb = ao2_alloc(sizeof(*cb), NULL);
662 cb->callbacks = callbacks;
663 ao2_link(wizard->observers, cb);
672 void ast_sorcery_wizard_observer_remove(struct ast_sorcery_wizard *interface,
673 const struct ast_sorcery_wizard_observer *callbacks)
675 RAII_VAR(struct ast_sorcery_internal_wizard *, wizard,
676 interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL,
680 ao2_callback(wizard->observers, OBJ_NODATA | OBJ_UNLINK, sorcery_generic_observer_remove, (void *)callbacks);
684 /*! \brief Destructor called when sorcery structure is destroyed */
685 static void sorcery_destructor(void *obj)
687 struct ast_sorcery *sorcery = obj;
689 if (sorcery->observers) {
690 NOTIFY_GLOBAL_OBSERVERS(observers, instance_destroying, sorcery->module_name, sorcery);
692 ao2_cleanup(sorcery->observers);
693 ao2_cleanup(sorcery->types);
696 /*! \brief Hashing function for sorcery types */
697 static int sorcery_type_hash(const void *obj, const int flags)
699 const struct ast_sorcery_object_type *object;
702 switch (flags & OBJ_SEARCH_MASK) {
706 case OBJ_SEARCH_OBJECT:
714 return ast_str_hash(key);
717 /*! \brief Comparator function for sorcery types */
718 static int sorcery_type_cmp(void *obj, void *arg, int flags)
720 const struct ast_sorcery_object_type *object_left = obj;
721 const struct ast_sorcery_object_type *object_right = arg;
722 const char *right_key = arg;
725 switch (flags & OBJ_SEARCH_MASK) {
726 case OBJ_SEARCH_OBJECT:
727 right_key = object_right->name;
730 cmp = strcmp(object_left->name, right_key);
732 case OBJ_SEARCH_PARTIAL_KEY:
733 cmp = strncmp(object_left->name, right_key, strlen(right_key));
745 struct ast_sorcery *__ast_sorcery_open(const char *module_name)
747 struct ast_sorcery *sorcery;
749 ast_assert(module_name != NULL);
751 ao2_wrlock(instances);
752 if ((sorcery = ao2_find(instances, module_name, OBJ_SEARCH_KEY | OBJ_NOLOCK))) {
756 if (!(sorcery = ao2_alloc(sizeof(*sorcery) + strlen(module_name) + 1, sorcery_destructor))) {
760 if (!(sorcery->types = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, TYPE_BUCKETS, sorcery_type_hash, sorcery_type_cmp))) {
761 ao2_ref(sorcery, -1);
766 if (!(sorcery->observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL))) {
767 ao2_ref(sorcery, -1);
772 strcpy(sorcery->module_name, module_name); /* Safe */
774 if (__ast_sorcery_apply_config(sorcery, module_name, module_name) == AST_SORCERY_APPLY_FAIL) {
775 ast_log(LOG_ERROR, "Error attempting to apply configuration %s to sorcery.\n", module_name);
776 ao2_cleanup(sorcery);
781 ao2_link_flags(instances, sorcery, OBJ_NOLOCK);
783 NOTIFY_GLOBAL_OBSERVERS(observers, instance_created, module_name, sorcery);
786 ao2_unlock(instances);
790 /*! \brief Search function for sorcery instances */
791 struct ast_sorcery *ast_sorcery_retrieve_by_module_name(const char *module_name)
793 return ao2_find(instances, module_name, OBJ_SEARCH_KEY);
796 /*! \brief Destructor function for object types */
797 static void sorcery_object_type_destructor(void *obj)
799 struct ast_sorcery_object_type *object_type = obj;
801 AST_VECTOR_RW_WRLOCK(&object_type->wizards);
802 AST_VECTOR_CALLBACK_VOID(&object_type->wizards, ao2_cleanup);
803 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
804 AST_VECTOR_RW_FREE(&object_type->wizards);
805 ao2_cleanup(object_type->fields);
806 ao2_cleanup(object_type->observers);
808 if (object_type->info) {
809 aco_info_destroy(object_type->info);
810 ast_free(object_type->info);
813 ast_free(object_type->file);
815 ast_taskprocessor_unreference(object_type->serializer);
818 /*! \brief Internal function which allocates an object type structure */
819 static struct ast_sorcery_object_type *sorcery_object_type_alloc(const char *type, const char *module)
821 #define INITIAL_WIZARD_VECTOR_SIZE 5
822 struct ast_sorcery_object_type *object_type;
823 char uuid[AST_UUID_STR_LEN];
825 if (!(object_type = ao2_alloc(sizeof(*object_type), sorcery_object_type_destructor))) {
829 /* Order matters for object wizards */
830 if (AST_VECTOR_RW_INIT(&object_type->wizards, INITIAL_WIZARD_VECTOR_SIZE) != 0) {
831 ao2_ref(object_type, -1);
835 if (!(object_type->fields = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, OBJECT_FIELD_BUCKETS,
836 object_type_field_hash, object_type_field_cmp))) {
837 ao2_ref(object_type, -1);
841 if (!(object_type->observers = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, 1, NULL, NULL))) {
842 ao2_ref(object_type, -1);
846 if (!(object_type->info = ast_calloc(1, sizeof(*object_type->info) + 2 * sizeof(object_type->info->files[0])))) {
847 ao2_ref(object_type, -1);
851 if (!(object_type->file = ast_calloc(1, sizeof(*object_type->file) + 2 * sizeof(object_type->file->types[0])))) {
852 ao2_ref(object_type, -1);
856 if (!ast_uuid_generate_str(uuid, sizeof(uuid))) {
857 ao2_ref(object_type, -1);
861 if (!(object_type->serializer = ast_threadpool_serializer(uuid, threadpool))) {
862 ao2_ref(object_type, -1);
866 object_type->info->files[0] = object_type->file;
867 object_type->info->files[1] = NULL;
868 object_type->info->module = module;
870 ast_copy_string(object_type->name, type, sizeof(object_type->name));
875 /*! \brief Object wizard destructor */
876 static void sorcery_object_wizard_destructor(void *obj)
878 struct ast_sorcery_object_wizard *object_wizard = obj;
880 if (object_wizard->data && object_wizard->wizard->callbacks.close) {
881 object_wizard->wizard->callbacks.close(object_wizard->data);
884 if (object_wizard->wizard) {
885 ast_module_unref(object_wizard->wizard->callbacks.module);
888 ao2_cleanup(object_wizard->wizard);
891 /*! \brief Return the number of wizards mapped to an object type */
892 int ast_sorcery_get_wizard_mapping_count(struct ast_sorcery *sorcery,
895 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
901 return AST_VECTOR_SIZE(&object_type->wizards);
904 int ast_sorcery_get_wizard_mapping(struct ast_sorcery *sorcery,
905 const char *type, int index, struct ast_sorcery_wizard **wizard, void **data)
907 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
908 struct ast_sorcery_object_wizard *owizard;
914 if (index < 0 || index >= AST_VECTOR_SIZE(&object_type->wizards)) {
918 owizard = AST_VECTOR_GET(&object_type->wizards, index);
920 if (wizard != NULL) {
921 *wizard = &(owizard->wizard->callbacks);
922 ao2_bump(owizard->wizard);
928 *data = owizard->data;
934 /*! \brief Internal function removes a wizard mapping */
935 int __ast_sorcery_remove_wizard_mapping(struct ast_sorcery *sorcery,
936 const char *type, const char *module, const char *name)
938 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
945 AST_VECTOR_RW_WRLOCK(&object_type->wizards);
946 #define WIZARD_NAME_COMPARE(a, b) (strcmp((a)->wizard->callbacks.name, (b)) == 0)
947 res = AST_VECTOR_REMOVE_CMP_ORDERED(&object_type->wizards, name, WIZARD_NAME_COMPARE, ao2_cleanup);
948 #undef WIZARD_NAME_COMPARE
949 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
954 /*! \brief Internal function which creates an object type and inserts a wizard mapping */
955 enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sorcery *sorcery,
956 const char *type, const char *module, const char *name, const char *data,
957 unsigned int caching, int position)
959 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
960 RAII_VAR(struct ast_sorcery_internal_wizard *, wizard, ao2_find(wizards, name, OBJ_KEY), ao2_cleanup);
961 RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, ao2_alloc(sizeof(*object_wizard), sorcery_object_wizard_destructor), ao2_cleanup);
965 ast_log(LOG_ERROR, "Wizard '%s' could not be applied to object type '%s' as it was not found\n",
967 return AST_SORCERY_APPLY_FAIL;
968 } else if (!object_wizard) {
969 return AST_SORCERY_APPLY_FAIL;
973 if (!(object_type = sorcery_object_type_alloc(type, module))) {
974 return AST_SORCERY_APPLY_FAIL;
979 AST_VECTOR_RW_WRLOCK(&object_type->wizards);
981 struct ast_sorcery_object_wizard *found;
983 #define WIZARD_COMPARE(a, b) ((a)->wizard == (b))
984 found = AST_VECTOR_GET_CMP(&object_type->wizards, wizard, WIZARD_COMPARE);
985 #undef WIZARD_COMPARE
987 ast_debug(1, "Wizard %s already applied to object type %s\n",
988 wizard->callbacks.name, object_type->name);
989 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
990 return AST_SORCERY_APPLY_DUPLICATE;
994 if (wizard->callbacks.open && !(object_wizard->data = wizard->callbacks.open(data))) {
995 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
996 return AST_SORCERY_APPLY_FAIL;
999 ast_module_ref(wizard->callbacks.module);
1001 object_wizard->wizard = ao2_bump(wizard);
1002 object_wizard->caching = caching;
1004 if (position == AST_SORCERY_WIZARD_POSITION_LAST) {
1005 position = AST_VECTOR_SIZE(&object_type->wizards);
1008 if (AST_VECTOR_INSERT_AT(&object_type->wizards, position, object_wizard) != 0) {
1009 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
1010 return AST_SORCERY_APPLY_FAIL;
1012 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
1013 ao2_bump(object_wizard);
1016 ao2_link(sorcery->types, object_type);
1019 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, wizard_mapped,
1020 sorcery->module_name, sorcery, type, &wizard->callbacks, data, object_wizard->data);
1022 return AST_SORCERY_APPLY_SUCCESS;
1025 /*! \brief Internal function which creates an object type and adds a wizard mapping */
1026 enum ast_sorcery_apply_result __ast_sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery,
1027 const char *type, const char *module, const char *name, const char *data, unsigned int caching)
1029 return __ast_sorcery_insert_wizard_mapping(sorcery, type, module, name, data,
1030 caching, AST_SORCERY_WIZARD_POSITION_LAST);
1033 enum ast_sorcery_apply_result __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, const char *module)
1035 struct ast_flags flags = { 0 };
1036 struct ast_config *config = ast_config_load2("sorcery.conf", "sorcery", flags);
1037 struct ast_variable *mapping;
1038 int res = AST_SORCERY_APPLY_SUCCESS;
1041 return AST_SORCERY_APPLY_NO_CONFIGURATION;
1044 if (config == CONFIG_STATUS_FILEINVALID) {
1045 return AST_SORCERY_APPLY_FAIL;
1048 for (mapping = ast_variable_browse(config, name); mapping; mapping = mapping->next) {
1049 RAII_VAR(char *, mapping_name, ast_strdup(mapping->name), ast_free);
1050 RAII_VAR(char *, mapping_value, ast_strdup(mapping->value), ast_free);
1051 char *options = mapping_name;
1052 char *type = strsep(&options, "/");
1053 char *data = mapping_value;
1054 char *wizard = strsep(&data, ",");
1055 unsigned int caching = 0;
1057 /* If no object type or wizard exists just skip, nothing we can do */
1058 if (ast_strlen_zero(type) || ast_strlen_zero(wizard)) {
1062 /* If the wizard is configured as a cache treat it as such */
1063 if (!ast_strlen_zero(options) && strstr(options, "cache")) {
1067 /* Any error immediately causes us to stop */
1068 if (__ast_sorcery_apply_wizard_mapping(sorcery, type, module, wizard, data, caching) == AST_SORCERY_APPLY_FAIL) {
1069 res = AST_SORCERY_APPLY_FAIL;
1074 ast_config_destroy(config);
1079 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)
1081 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1083 /* Defaults can not be added if any existing mapping exists */
1085 return AST_SORCERY_APPLY_DEFAULT_UNNECESSARY;
1088 return __ast_sorcery_apply_wizard_mapping(sorcery, type, module, name, data, 0);
1091 static int sorcery_extended_config_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1093 return ast_sorcery_object_set_extended(obj, var->name, var->value);
1096 static int sorcery_extended_fields_handler(const void *obj, struct ast_variable **fields)
1098 const struct ast_sorcery_object_details *details = obj;
1100 if (details->object->extended) {
1101 *fields = ast_variables_dup(details->object->extended);
1109 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)
1111 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1113 if (!object_type || object_type->type.item_alloc) {
1117 object_type->type.name = object_type->name;
1118 object_type->type.type = ACO_ITEM;
1119 object_type->type.category = ".?";
1120 object_type->type.item_alloc = alloc;
1121 object_type->type.hidden = hidden;
1123 object_type->reloadable = reloadable;
1124 object_type->transform = transform;
1125 object_type->apply = apply;
1126 object_type->file->types[0] = &object_type->type;
1127 object_type->file->types[1] = NULL;
1129 if (aco_info_init(object_type->info)) {
1133 if (ast_sorcery_object_fields_register(sorcery, type, "^@", sorcery_extended_config_handler, sorcery_extended_fields_handler)) {
1137 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, object_type_registered,
1138 sorcery->module_name, sorcery, type);
1143 void ast_sorcery_object_set_copy_handler(struct ast_sorcery *sorcery, const char *type, sorcery_copy_handler copy)
1145 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1151 object_type->copy = copy;
1154 void ast_sorcery_object_set_diff_handler(struct ast_sorcery *sorcery, const char *type, sorcery_diff_handler diff)
1156 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1162 object_type->diff = diff;
1165 static void sorcery_object_field_destructor(void *obj)
1167 struct ast_sorcery_object_field *object_field = obj;
1169 if (object_field->name_regex) {
1170 regfree(object_field->name_regex);
1171 ast_free(object_field->name_regex);
1175 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)
1177 #define MAX_REGEX_ERROR_LEN 128
1178 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1179 RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, ao2_cleanup);
1182 if (!object_type || !object_type->type.item_alloc || !config_handler
1183 || !(object_field = ao2_alloc(sizeof(*object_field), sorcery_object_field_destructor))) {
1187 ast_copy_string(object_field->name, regex, sizeof(object_field->name));
1188 object_field->multiple_handler = sorcery_handler;
1190 if (!(object_field->name_regex = ast_calloc(1, sizeof(regex_t)))) {
1194 if ((rc = regcomp(object_field->name_regex, regex, REG_EXTENDED | REG_NOSUB))) {
1195 char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
1196 regerror(rc, object_field->name_regex, regerr, MAX_REGEX_ERROR_LEN);
1197 ast_log(LOG_ERROR, "Regular expression '%s' failed to compile: %s\n", regex, regerr);
1201 ao2_link(object_type->fields, object_field);
1202 __aco_option_register(object_type->info, regex, ACO_REGEX, object_type->file->types, "", OPT_CUSTOM_T, config_handler, 0, 1, 0);
1207 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,
1208 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, ...)
1210 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1211 RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, ao2_cleanup);
1215 if (!strcmp(type, "id") || !object_type || !object_type->type.item_alloc) {
1219 if (!sorcery_handler) {
1220 sorcery_handler = sorcery_field_default_handler(opt_type);
1223 if (!(object_field = ao2_alloc(sizeof(*object_field) + argc * sizeof(object_field->args[0]), NULL))) {
1227 ast_copy_string(object_field->name, name, sizeof(object_field->name));
1228 object_field->handler = sorcery_handler;
1229 object_field->multiple_handler = multiple_handler;
1231 va_start(args, argc);
1232 for (pos = 0; pos < argc; pos++) {
1233 object_field->args[pos] = va_arg(args, size_t);
1238 ao2_link(object_type->fields, object_field);
1241 /* TODO: Improve this hack */
1243 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc);
1244 } else if (argc == 1) {
1245 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
1246 object_field->args[0]);
1247 } else if (argc == 2) {
1248 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
1249 object_field->args[0], object_field->args[1]);
1250 } else if (argc == 3) {
1251 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
1252 object_field->args[0], object_field->args[1], object_field->args[2]);
1254 ast_assert(0); /* The hack... she does us no good for this */
1260 /*! \brief Retrieves whether or not the type is reloadable */
1261 static int sorcery_reloadable(const struct ast_sorcery *sorcery, const char *type)
1263 RAII_VAR(struct ast_sorcery_object_type *, object_type,
1264 ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1265 return object_type && object_type->reloadable;
1268 static int sorcery_wizard_load(void *obj, void *arg, int flags)
1270 struct ast_sorcery_object_wizard *wizard = obj;
1271 struct sorcery_load_details *details = arg;
1272 void (*load)(void *data, const struct ast_sorcery *sorcery, const char *type);
1274 load = !details->reload ? wizard->wizard->callbacks.load : wizard->wizard->callbacks.reload;
1277 NOTIFY_WIZARD_OBSERVERS(wizard->wizard->observers, wizard_loading,
1278 wizard->wizard->callbacks.name, &wizard->wizard->callbacks, details->type, details->reload);
1280 load(wizard->data, details->sorcery, details->type);
1282 NOTIFY_WIZARD_OBSERVERS(wizard->wizard->observers, wizard_loaded,
1283 wizard->wizard->callbacks.name, &wizard->wizard->callbacks, details->type, details->reload);
1289 /*! \brief Destructor for observer invocation */
1290 static void sorcery_observer_invocation_destroy(void *obj)
1292 struct sorcery_observer_invocation *invocation = obj;
1294 ao2_cleanup(invocation->object_type);
1295 ao2_cleanup(invocation->object);
1298 /*! \brief Allocator function for observer invocation */
1299 static struct sorcery_observer_invocation *sorcery_observer_invocation_alloc(struct ast_sorcery_object_type *object_type, void *object)
1301 struct sorcery_observer_invocation *invocation = ao2_alloc(sizeof(*invocation), sorcery_observer_invocation_destroy);
1307 ao2_ref(object_type, +1);
1308 invocation->object_type = object_type;
1311 ao2_ref(object, +1);
1312 invocation->object = object;
1318 /*! \brief Internal callback function which notifies an individual observer that an object type has been loaded */
1319 static int sorcery_observer_notify_loaded(void *obj, void *arg, int flags)
1321 const struct ast_sorcery_object_type_observer *observer = obj;
1323 if (observer->callbacks->loaded) {
1324 observer->callbacks->loaded(arg);
1330 /*! \brief Internal callback function which notifies observers that an object type has been loaded */
1331 static int sorcery_observers_notify_loaded(void *data)
1333 struct sorcery_observer_invocation *invocation = data;
1335 ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_loaded, invocation->object_type->name);
1336 ao2_cleanup(invocation);
1341 static int sorcery_object_load(void *obj, void *arg, int flags)
1343 struct ast_sorcery_object_type *type = obj;
1344 struct sorcery_load_details *details = arg;
1346 if (!type->type.item_alloc) {
1350 details->type = type->name;
1352 if (details->reload && !sorcery_reloadable(details->sorcery, details->type)) {
1353 ast_log(LOG_NOTICE, "Type '%s' is not reloadable, maintaining previous values\n",
1358 NOTIFY_INSTANCE_OBSERVERS(details->sorcery->observers, object_type_loading,
1359 details->sorcery->module_name, details->sorcery, type->name, details->reload);
1361 AST_VECTOR_RW_RDLOCK(&type->wizards);
1362 AST_VECTOR_CALLBACK(&type->wizards, sorcery_wizard_load, NULL, details, 0);
1363 AST_VECTOR_RW_UNLOCK(&type->wizards);
1365 NOTIFY_INSTANCE_OBSERVERS(details->sorcery->observers, object_type_loaded,
1366 details->sorcery->module_name, details->sorcery, type->name, details->reload);
1368 if (ao2_container_count(type->observers)) {
1369 struct sorcery_observer_invocation *invocation;
1371 invocation = sorcery_observer_invocation_alloc(type, NULL);
1373 && ast_taskprocessor_push(type->serializer, sorcery_observers_notify_loaded,
1375 ao2_cleanup(invocation);
1382 void ast_sorcery_load(const struct ast_sorcery *sorcery)
1384 struct sorcery_load_details details = {
1389 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loading,
1390 sorcery->module_name, sorcery, 0);
1392 ao2_callback(sorcery->types, OBJ_NODATA, sorcery_object_load, &details);
1394 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loaded,
1395 sorcery->module_name, sorcery, 0);
1398 void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type)
1400 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1401 struct sorcery_load_details details = {
1410 sorcery_object_load(object_type, &details, 0);
1413 void ast_sorcery_reload(const struct ast_sorcery *sorcery)
1415 struct sorcery_load_details details = {
1420 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loading,
1421 sorcery->module_name, sorcery, 1);
1423 ao2_callback(sorcery->types, OBJ_NODATA, sorcery_object_load, &details);
1425 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loaded,
1426 sorcery->module_name, sorcery, 1);
1430 void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
1432 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1433 struct sorcery_load_details details = {
1442 sorcery_object_load(object_type, &details, 0);
1445 void ast_sorcery_ref(struct ast_sorcery *sorcery)
1447 ao2_ref(sorcery, +1);
1450 static struct ast_variable *get_single_field_as_var_list(const void *object, struct ast_sorcery_object_field *object_field)
1452 struct ast_variable *tmp = NULL;
1455 if (!object_field->handler) {
1459 if (!(object_field->handler(object, object_field->args, &buf))) {
1460 tmp = ast_variable_new(object_field->name, S_OR(buf, ""), "");
1467 static struct ast_variable *get_multiple_fields_as_var_list(const void *object, struct ast_sorcery_object_field *object_field)
1469 struct ast_variable *tmp = NULL;
1471 if (!object_field->multiple_handler) {
1475 if (object_field->multiple_handler(object, &tmp)) {
1476 ast_variables_destroy(tmp);
1483 struct ast_variable *ast_sorcery_objectset_create2(const struct ast_sorcery *sorcery,
1484 const void *object, enum ast_sorcery_field_handler_flags flags)
1486 const struct ast_sorcery_object_details *details = object;
1487 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1488 struct ao2_iterator i;
1489 struct ast_sorcery_object_field *object_field;
1490 struct ast_variable *head = NULL;
1491 struct ast_variable *tail = NULL;
1497 i = ao2_iterator_init(object_type->fields, 0);
1499 for (; (object_field = ao2_iterator_next(&i)); ao2_ref(object_field, -1)) {
1500 struct ast_variable *tmp;
1503 case AST_HANDLER_PREFER_LIST:
1504 if ((tmp = get_multiple_fields_as_var_list(object, object_field)) ||
1505 (tmp = get_single_field_as_var_list(object, object_field))) {
1509 case AST_HANDLER_PREFER_STRING:
1510 if ((tmp = get_single_field_as_var_list(object, object_field)) ||
1511 (tmp = get_multiple_fields_as_var_list(object, object_field))) {
1515 case AST_HANDLER_ONLY_LIST:
1516 if ((tmp = get_multiple_fields_as_var_list(object, object_field))) {
1520 case AST_HANDLER_ONLY_STRING:
1521 if ((tmp = get_single_field_as_var_list(object, object_field))) {
1529 tail = ast_variable_list_append_hint(&head, tail, tmp);
1532 ao2_iterator_destroy(&i);
1537 struct ast_json *ast_sorcery_objectset_json_create(const struct ast_sorcery *sorcery, const void *object)
1539 const struct ast_sorcery_object_details *details = object;
1540 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1541 struct ao2_iterator i;
1542 struct ast_sorcery_object_field *object_field;
1543 struct ast_json *json = ast_json_object_create();
1546 if (!object_type || !json) {
1550 i = ao2_iterator_init(object_type->fields, 0);
1552 for (; !res && (object_field = ao2_iterator_next(&i)); ao2_ref(object_field, -1)) {
1553 if (object_field->multiple_handler) {
1554 struct ast_variable *tmp = NULL;
1555 struct ast_variable *field;
1557 if ((res = object_field->multiple_handler(object, &tmp))) {
1558 ast_variables_destroy(tmp);
1559 ao2_ref(object_field, -1);
1563 for (field = tmp; field; field = field->next) {
1564 struct ast_json *value = ast_json_string_create(field->value);
1566 if (!value || ast_json_object_set(json, field->name, value)) {
1572 ast_variables_destroy(tmp);
1573 } else if (object_field->handler) {
1575 struct ast_json *value = NULL;
1577 if ((res = object_field->handler(object, object_field->args, &buf))
1578 || !(value = ast_json_string_create(buf))
1579 || ast_json_object_set(json, object_field->name, value)) {
1589 ao2_iterator_destroy(&i);
1591 /* If any error occurs we destroy the JSON object so a partial objectset is not returned */
1593 ast_json_unref(json);
1600 int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object, struct ast_variable *objectset)
1602 const struct ast_sorcery_object_details *details = object;
1603 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1604 RAII_VAR(struct ast_variable *, transformed, NULL, ast_variables_destroy);
1605 struct ast_variable *field;
1612 if (object_type->transform && (transformed = object_type->transform(objectset))) {
1613 field = transformed;
1618 for (; field; field = field->next) {
1619 if ((res = aco_process_var(&object_type->type, details->object->id, field, object))) {
1624 if (!res && object_type->apply) {
1625 res = object_type->apply(sorcery, object);
1631 int ast_sorcery_changeset_create(const struct ast_variable *original, const struct ast_variable *modified, struct ast_variable **changes)
1633 const struct ast_variable *field;
1638 /* Unless the ast_variable list changes when examined... it can't differ from itself */
1639 if (original == modified) {
1643 for (field = modified; field; field = field->next) {
1644 const char *old_value = ast_variable_find_in_list(original, field->name);
1646 if (!old_value || strcmp(old_value, field->value)) {
1647 struct ast_variable *tmp;
1649 if (!(tmp = ast_variable_new(field->name, field->value, ""))) {
1654 tmp->next = *changes;
1659 /* If an error occurred do not return a partial changeset */
1661 ast_variables_destroy(*changes);
1668 static void sorcery_object_destructor(void *object)
1670 struct ast_sorcery_object_details *details = object;
1672 if (details->object->destructor) {
1673 details->object->destructor(object);
1676 ast_variables_destroy(details->object->extended);
1677 ast_free(details->object->id);
1680 void *ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
1682 void *object = ao2_alloc_options(size + sizeof(struct ast_sorcery_object), sorcery_object_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
1683 struct ast_sorcery_object_details *details = object;
1689 details->object = object + size;
1690 details->object->destructor = destructor;
1695 void *ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
1697 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1698 struct ast_sorcery_object_details *details;
1700 if (!object_type || !object_type->type.item_alloc ||
1701 !(details = object_type->type.item_alloc(id))) {
1705 if (ast_strlen_zero(id)) {
1706 char uuid[AST_UUID_STR_LEN];
1708 ast_uuid_generate_str(uuid, sizeof(uuid));
1709 details->object->id = ast_strdup(uuid);
1711 details->object->id = ast_strdup(id);
1714 ast_copy_string(details->object->type, type, sizeof(details->object->type));
1716 if (aco_set_defaults(&object_type->type, id, details)) {
1717 ao2_ref(details, -1);
1724 void *ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
1726 const struct ast_sorcery_object_details *details = object;
1727 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1728 struct ast_sorcery_object_details *copy = ast_sorcery_alloc(sorcery, details->object->type, details->object->id);
1729 RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy);
1734 } else if (object_type->copy) {
1735 res = object_type->copy(object, copy);
1736 } else if ((objectset = ast_sorcery_objectset_create(sorcery, object))) {
1737 res = ast_sorcery_objectset_apply(sorcery, copy, objectset);
1739 /* No native copy available and could not create an objectset, this copy has failed */
1751 int ast_sorcery_diff(const struct ast_sorcery *sorcery, const void *original, const void *modified, struct ast_variable **changes)
1753 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, ast_sorcery_object_get_type(original), OBJ_KEY), ao2_cleanup);
1757 if (strcmp(ast_sorcery_object_get_type(original), ast_sorcery_object_get_type(modified))) {
1761 if (original == modified) {
1763 } else if (!object_type->diff) {
1764 RAII_VAR(struct ast_variable *, objectset1, NULL, ast_variables_destroy);
1765 RAII_VAR(struct ast_variable *, objectset2, NULL, ast_variables_destroy);
1767 objectset1 = ast_sorcery_objectset_create(sorcery, original);
1768 objectset2 = ast_sorcery_objectset_create(sorcery, modified);
1770 return ast_sorcery_changeset_create(objectset1, objectset2, changes);
1772 return object_type->diff(original, modified, changes);
1776 /*! \brief Structure used when calling create, update, or delete */
1777 struct sorcery_details {
1778 /*! \brief Pointer to the sorcery instance */
1779 const struct ast_sorcery *sorcery;
1780 /*! \brief Pointer to the object itself */
1784 /*! \brief Internal function used to create an object in caching wizards */
1785 static int sorcery_cache_create(void *obj, void *arg, int flags)
1787 const struct ast_sorcery_object_wizard *object_wizard = obj;
1788 const struct sorcery_details *details = arg;
1790 if (!object_wizard->caching || !object_wizard->wizard->callbacks.create) {
1794 object_wizard->wizard->callbacks.create(details->sorcery, object_wizard->data, details->obj);
1799 void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
1801 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1802 void *object = NULL;
1804 unsigned int cached = 0;
1806 if (!object_type || ast_strlen_zero(id)) {
1810 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
1811 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
1812 struct ast_sorcery_object_wizard *wizard =
1813 AST_VECTOR_GET(&object_type->wizards, i);
1815 if (wizard->wizard->callbacks.retrieve_id &&
1816 !(object = wizard->wizard->callbacks.retrieve_id(sorcery, wizard->data, object_type->name, id))) {
1820 cached = wizard->caching;
1824 if (!cached && object) {
1825 AST_VECTOR_CALLBACK(&object_type->wizards, sorcery_cache_create, NULL, object, 0);
1827 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
1832 void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
1834 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1835 void *object = NULL;
1837 unsigned int cached = 0;
1843 /* If returning multiple objects create a container to store them in */
1844 if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
1845 if (!(object = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
1850 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
1851 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
1852 struct ast_sorcery_object_wizard *wizard =
1853 AST_VECTOR_GET(&object_type->wizards, i);
1855 if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
1856 if (wizard->wizard->callbacks.retrieve_multiple) {
1857 wizard->wizard->callbacks.retrieve_multiple(sorcery, wizard->data, object_type->name, object, fields);
1859 } else if (fields && wizard->wizard->callbacks.retrieve_fields) {
1860 if (wizard->wizard->callbacks.retrieve_fields) {
1861 object = wizard->wizard->callbacks.retrieve_fields(sorcery, wizard->data, object_type->name, fields);
1865 if ((flags & AST_RETRIEVE_FLAG_MULTIPLE) || !object) {
1869 cached = wizard->caching;
1874 /* If we are returning a single object and it came from a non-cache source create it in any caches */
1875 if (!(flags & AST_RETRIEVE_FLAG_MULTIPLE) && !cached && object) {
1876 AST_VECTOR_CALLBACK(&object_type->wizards, sorcery_cache_create, NULL, object, 0);
1878 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
1883 struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex)
1885 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1886 struct ao2_container *objects;
1889 if (!object_type || !(objects = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
1893 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
1894 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
1895 struct ast_sorcery_object_wizard *wizard =
1896 AST_VECTOR_GET(&object_type->wizards, i);
1898 if (!wizard->wizard->callbacks.retrieve_regex) {
1902 wizard->wizard->callbacks.retrieve_regex(sorcery, wizard->data, object_type->name, objects, regex);
1904 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
1909 /*! \brief Internal function which returns if the wizard has created the object */
1910 static int sorcery_wizard_create(void *obj, void *arg, int flags)
1912 const struct ast_sorcery_object_wizard *object_wizard = obj;
1913 const struct sorcery_details *details = arg;
1915 if (!object_wizard->wizard->callbacks.create) {
1917 ast_log(LOG_ERROR, "Sorcery wizard '%s' doesn't contain a 'create' virtual function.\n",
1918 object_wizard->wizard->callbacks.name);
1921 return (!object_wizard->caching && !object_wizard->wizard->callbacks.create(details->sorcery, object_wizard->data, details->obj)) ? CMP_MATCH | CMP_STOP : 0;
1924 /*! \brief Internal callback function which notifies an individual observer that an object has been created */
1925 static int sorcery_observer_notify_create(void *obj, void *arg, int flags)
1927 const struct ast_sorcery_object_type_observer *observer = obj;
1929 if (observer->callbacks->created) {
1930 observer->callbacks->created(arg);
1936 /*! \brief Internal callback function which notifies observers that an object has been created */
1937 static int sorcery_observers_notify_create(void *data)
1939 struct sorcery_observer_invocation *invocation = data;
1941 ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_create, invocation->object);
1942 ao2_cleanup(invocation);
1947 int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
1949 const struct ast_sorcery_object_details *details = object;
1950 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1951 struct ast_sorcery_object_wizard *object_wizard = NULL;
1952 struct ast_sorcery_object_wizard *found_wizard;
1954 struct sorcery_details sdetails = {
1963 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
1964 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
1965 found_wizard = AST_VECTOR_GET(&object_type->wizards, i);
1966 if (sorcery_wizard_create(found_wizard, &sdetails, 0) == (CMP_MATCH | CMP_STOP)) {
1967 object_wizard = found_wizard;
1968 if(ao2_container_count(object_type->observers)) {
1969 struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
1971 if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_create, invocation)) {
1972 ao2_cleanup(invocation);
1977 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
1979 return object_wizard ? 0 : -1;
1982 /*! \brief Internal callback function which notifies an individual observer that an object has been updated */
1983 static int sorcery_observer_notify_update(void *obj, void *arg, int flags)
1985 const struct ast_sorcery_object_type_observer *observer = obj;
1987 if (observer->callbacks->updated) {
1988 observer->callbacks->updated(arg);
1994 /*! \brief Internal callback function which notifies observers that an object has been updated */
1995 static int sorcery_observers_notify_update(void *data)
1997 struct sorcery_observer_invocation *invocation = data;
1999 ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_update, invocation->object);
2000 ao2_cleanup(invocation);
2005 /*! \brief Internal function which returns if a wizard has updated the object */
2006 static int sorcery_wizard_update(void *obj, void *arg, int flags)
2008 const struct ast_sorcery_object_wizard *object_wizard = obj;
2009 const struct sorcery_details *details = arg;
2011 return (object_wizard->wizard->callbacks.update && !object_wizard->wizard->callbacks.update(details->sorcery, object_wizard->data, details->obj) &&
2012 !object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0;
2015 int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
2017 const struct ast_sorcery_object_details *details = object;
2018 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
2019 struct ast_sorcery_object_wizard *object_wizard = NULL;
2020 struct ast_sorcery_object_wizard *found_wizard;
2022 struct sorcery_details sdetails = {
2031 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
2032 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
2033 found_wizard = AST_VECTOR_GET(&object_type->wizards, i);
2034 if (sorcery_wizard_update(found_wizard, &sdetails, 0) == (CMP_MATCH | CMP_STOP)) {
2035 object_wizard = found_wizard;
2036 if (ao2_container_count(object_type->observers)) {
2037 struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
2039 if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_update, invocation)) {
2040 ao2_cleanup(invocation);
2045 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
2047 return object_wizard ? 0 : -1;
2050 /*! \brief Internal callback function which notifies an individual observer that an object has been deleted */
2051 static int sorcery_observer_notify_delete(void *obj, void *arg, int flags)
2053 const struct ast_sorcery_object_type_observer *observer = obj;
2055 if (observer->callbacks->deleted) {
2056 observer->callbacks->deleted(arg);
2062 /*! \brief Internal callback function which notifies observers that an object has been deleted */
2063 static int sorcery_observers_notify_delete(void *data)
2065 struct sorcery_observer_invocation *invocation = data;
2067 ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_delete, invocation->object);
2068 ao2_cleanup(invocation);
2073 /*! \brief Internal function which returns if a wizard has deleted the object */
2074 static int sorcery_wizard_delete(void *obj, void *arg, int flags)
2076 const struct ast_sorcery_object_wizard *object_wizard = obj;
2077 const struct sorcery_details *details = arg;
2079 return (object_wizard->wizard->callbacks.delete && !object_wizard->wizard->callbacks.delete(details->sorcery, object_wizard->data, details->obj) &&
2080 !object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0;
2083 int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
2085 const struct ast_sorcery_object_details *details = object;
2086 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
2087 struct ast_sorcery_object_wizard *object_wizard = NULL;
2088 struct ast_sorcery_object_wizard *found_wizard;
2090 struct sorcery_details sdetails = {
2099 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
2100 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
2101 found_wizard = AST_VECTOR_GET(&object_type->wizards, i);
2102 if (sorcery_wizard_delete(found_wizard, &sdetails, 0) == (CMP_MATCH | CMP_STOP)) {
2103 object_wizard = found_wizard;
2104 if (ao2_container_count(object_type->observers)) {
2105 struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
2107 if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_delete, invocation)) {
2108 ao2_cleanup(invocation);
2113 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
2115 return object_wizard ? 0 : -1;
2118 void ast_sorcery_unref(struct ast_sorcery *sorcery)
2121 /* One ref for what we just released, the other for the instances container. */
2122 ao2_wrlock(instances);
2123 if (ao2_ref(sorcery, -1) == 2) {
2124 ao2_unlink_flags(instances, sorcery, OBJ_NOLOCK);
2126 ao2_unlock(instances);
2130 const char *ast_sorcery_object_get_id(const void *object)
2132 const struct ast_sorcery_object_details *details = object;
2133 return details->object->id;
2136 const char *ast_sorcery_object_get_type(const void *object)
2138 const struct ast_sorcery_object_details *details = object;
2139 return details->object->type;
2142 const char *ast_sorcery_object_get_extended(const void *object, const char *name)
2144 const struct ast_sorcery_object_details *details = object;
2145 struct ast_variable *field;
2147 for (field = details->object->extended; field; field = field->next) {
2148 if (!strcmp(field->name + 1, name)) {
2149 return field->value;
2156 int ast_sorcery_object_set_extended(const void *object, const char *name, const char *value)
2158 RAII_VAR(struct ast_variable *, field, NULL, ast_variables_destroy);
2159 struct ast_variable *extended = ast_variable_new(name, value, ""), *previous = NULL;
2160 const struct ast_sorcery_object_details *details = object;
2166 for (field = details->object->extended; field; previous = field, field = field->next) {
2167 if (!strcmp(field->name, name)) {
2169 previous->next = field->next;
2171 details->object->extended = field->next;
2178 extended->next = details->object->extended;
2179 details->object->extended = extended;
2184 int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
2186 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
2187 struct ast_sorcery_object_type_observer *observer;
2190 if (!object_type || !callbacks) {
2194 if (!(observer = ao2_alloc(sizeof(*observer), NULL))) {
2198 observer->callbacks = callbacks;
2200 if (!ao2_link(object_type->observers, observer)) {
2203 ao2_ref(observer, -1);
2208 /*! \brief Internal callback function for removing an observer */
2209 static int sorcery_observer_remove(void *obj, void *arg, int flags)
2211 const struct ast_sorcery_object_type_observer *observer = obj;
2213 return (observer->callbacks == arg) ? CMP_MATCH | CMP_STOP : 0;
2216 void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
2218 RAII_VAR(struct ast_sorcery_object_type *, object_type, NULL, ao2_cleanup);
2219 struct ast_sorcery_observer *cbs = (struct ast_sorcery_observer *) callbacks;/* Remove const for traversal. */
2224 object_type = ao2_find(sorcery->types, type, OBJ_KEY);
2229 ao2_callback(object_type->observers, OBJ_NODATA | OBJ_UNLINK,
2230 sorcery_observer_remove, cbs);
2233 int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
2235 const char *right_key = arg;
2238 switch (flags & OBJ_SEARCH_MASK) {
2239 case OBJ_SEARCH_OBJECT:
2240 right_key = ast_sorcery_object_get_id(arg);
2242 case OBJ_SEARCH_KEY:
2243 cmp = strcmp(ast_sorcery_object_get_id(obj), right_key);
2245 case OBJ_SEARCH_PARTIAL_KEY:
2246 cmp = strncmp(ast_sorcery_object_get_id(obj), right_key, strlen(right_key));
2255 int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
2257 const char *right_key = arg;
2260 switch (flags & OBJ_SEARCH_MASK) {
2261 case OBJ_SEARCH_OBJECT:
2262 right_key = ast_sorcery_object_get_id(arg);
2264 case OBJ_SEARCH_KEY:
2265 if (strcmp(ast_sorcery_object_get_id(obj), right_key) == 0) {
2266 cmp = CMP_MATCH | CMP_STOP;
2269 case OBJ_SEARCH_PARTIAL_KEY:
2270 if (strncmp(ast_sorcery_object_get_id(obj), right_key, strlen(right_key)) == 0) {
2281 int ast_sorcery_object_id_hash(const void *obj, int flags) {
2282 if (flags & OBJ_SEARCH_OBJECT) {
2283 return ast_str_hash(ast_sorcery_object_get_id(obj));
2284 } else if (flags & OBJ_SEARCH_KEY) {
2285 return ast_str_hash(obj);
2290 struct ast_sorcery_object_type *ast_sorcery_get_object_type(const struct ast_sorcery *sorcery,
2293 return ao2_find(sorcery->types, type, OBJ_SEARCH_KEY);
2296 static int is_registered_cb(void *obj, void *arg, int flags)
2298 struct ast_sorcery_object_field *object_field = obj;
2302 if (object_field->name_regex
2303 && !regexec(object_field->name_regex, name, 0, NULL, 0)) {
2304 rc = CMP_MATCH | CMP_STOP;
2310 int ast_sorcery_is_object_field_registered(const struct ast_sorcery_object_type *object_type,
2311 const char *field_name)
2313 struct ast_sorcery_object_field *object_field;
2316 ast_assert(object_type != NULL);
2318 object_field = ao2_find(object_type->fields, field_name, OBJ_SEARCH_KEY);
2320 if (!object_field) {
2321 object_field = ao2_callback(object_type->fields, 0, is_registered_cb, (char *)field_name);
2324 if (!object_field) {
2328 ao2_cleanup(object_field);
2332 const char *ast_sorcery_get_module(const struct ast_sorcery *sorcery)
2334 return sorcery->module_name;