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;
133 /*! \brief Time that the object was created */
134 struct timeval created;
137 /*! \brief Structure for registered object type */
138 struct ast_sorcery_object_type {
139 /*! \brief Unique name of the object type */
140 char name[MAX_OBJECT_TYPE];
142 /*! \brief Optional transformation callback */
143 sorcery_transform_handler transform;
145 /*! \brief Optional object set apply callback */
146 sorcery_apply_handler apply;
148 /*! \brief Optional object copy callback */
149 sorcery_copy_handler copy;
151 /*! \brief Optional object diff callback */
152 sorcery_diff_handler diff;
154 /*! \brief Wizard instances */
155 struct ast_sorcery_object_wizards wizards;
157 /*! \brief Object fields */
158 struct ao2_container *fields;
160 /*! \brief Configuration framework general information */
161 struct aco_info *info;
163 /*! \brief Configuration framework file information */
164 struct aco_file *file;
166 /*! \brief Type details */
167 struct aco_type type;
169 /*! \brief Observers */
170 struct ao2_container *observers;
172 /*! \brief Serializer for observers */
173 struct ast_taskprocessor *serializer;
175 /*! \brief Specifies if object type is reloadable or not */
176 unsigned int reloadable:1;
179 /*! \brief Structure for registered object type observer */
180 struct ast_sorcery_object_type_observer {
181 /*! \brief Pointer to the observer implementation */
182 const struct ast_sorcery_observer *callbacks;
185 /*! \brief Structure used for observer invocations */
186 struct sorcery_observer_invocation {
187 /*! \brief Pointer to the object type */
188 struct ast_sorcery_object_type *object_type;
190 /*! \brief Pointer to the object */
194 /*! \brief Structure for registered object field */
195 struct ast_sorcery_object_field {
196 /*! \brief Name of the field */
197 char name[MAX_OBJECT_FIELD];
199 /*! \brief The compiled name regex if name is a regex */
202 /*! \brief Callback function for translation of a single value */
203 sorcery_field_handler handler;
205 /*! \brief Callback function for translation of multiple values */
206 sorcery_fields_handler multiple_handler;
208 /*! \brief Position of the field */
212 /*! \brief Full structure for sorcery */
214 /*! \brief Container for known object types */
215 struct ao2_container *types;
217 /*! \brief Observers */
218 struct ao2_container *observers;
220 /*! \brief The name of the module owning this sorcery instance */
224 /*! \brief Structure for passing load/reload details */
225 struct sorcery_load_details {
226 /*! \brief Sorcery structure in use */
227 const struct ast_sorcery *sorcery;
229 /*! \brief Type of object being loaded */
232 /*! \brief Whether this is a reload or not */
233 unsigned int reload:1;
236 /*! \brief Registered sorcery wizards */
237 static struct ao2_container *wizards;
239 /* The following 3 observer wrappers must name their
240 * external observer 'callbacks' and it must be
241 * the first member of the structure. Common macros
242 * and container callbacks depend on it.
245 /*! \brief A global observer wrapper */
246 struct sorcery_global_observer {
247 const struct ast_sorcery_global_observer *callbacks;
250 /*! \brief An instance observer wrapper */
251 struct sorcery_instance_observer {
252 const struct ast_sorcery_instance_observer *callbacks;
255 /*! \brief A wizard observer wrapper */
256 struct sorcery_wizard_observer {
257 const struct ast_sorcery_wizard_observer *callbacks;
260 /*! \brief Registered global observers */
261 struct ao2_container *observers;
263 /*! \brief Registered sorcery instances */
264 static struct ao2_container *instances;
266 static int int_handler_fn(const void *obj, const intptr_t *args, char **buf)
268 int *field = (int *)(obj + args[0]);
269 return (ast_asprintf(buf, "%d", *field) < 0) ? -1 : 0;
272 static int uint_handler_fn(const void *obj, const intptr_t *args, char **buf)
274 unsigned int *field = (unsigned int *)(obj + args[0]);
275 return (ast_asprintf(buf, "%u", *field) < 0) ? -1 : 0;
278 static int double_handler_fn(const void *obj, const intptr_t *args, char **buf)
280 double *field = (double *)(obj + args[0]);
281 return (ast_asprintf(buf, "%f", *field) < 0) ? -1 : 0;
284 static int stringfield_handler_fn(const void *obj, const intptr_t *args, char **buf)
286 ast_string_field *field = (const char **)(obj + args[0]);
287 return !(*buf = ast_strdup(*field)) ? -1 : 0;
290 static int bool_handler_fn(const void *obj, const intptr_t *args, char **buf)
292 unsigned int *field = (unsigned int *)(obj + args[0]);
293 return !(*buf = ast_strdup(*field ? "true" : "false")) ? -1 : 0;
296 static int sockaddr_handler_fn(const void *obj, const intptr_t *args, char **buf)
298 struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + args[0]);
299 return !(*buf = ast_strdup(ast_sockaddr_stringify(field))) ? -1 : 0;
302 static int chararray_handler_fn(const void *obj, const intptr_t *args, char **buf)
304 char *field = (char *)(obj + args[0]);
305 return !(*buf = ast_strdup(field)) ? -1 : 0;
308 static int codec_handler_fn(const void *obj, const intptr_t *args, char **buf)
310 struct ast_str *codec_buf = ast_str_alloca(64);
311 struct ast_format_cap **cap = (struct ast_format_cap **)(obj + args[0]);
312 return !(*buf = ast_strdup(ast_format_cap_get_names(*cap, &codec_buf)));
315 static sorcery_field_handler sorcery_field_default_handler(enum aco_option_type type)
318 case OPT_BOOL_T: return bool_handler_fn;
319 case OPT_CHAR_ARRAY_T: return chararray_handler_fn;
320 case OPT_CODEC_T: return codec_handler_fn;
321 case OPT_DOUBLE_T: return double_handler_fn;
322 case OPT_INT_T: return int_handler_fn;
323 case OPT_SOCKADDR_T: return sockaddr_handler_fn;
324 case OPT_STRINGFIELD_T: return stringfield_handler_fn;
325 case OPT_UINT_T: return uint_handler_fn;
328 case OPT_CUSTOM_T: return NULL;
334 /*! \brief Hashing function for sorcery wizards */
335 static int sorcery_wizard_hash(const void *obj, const int flags)
337 const struct ast_sorcery_internal_wizard *object;
340 switch (flags & OBJ_SEARCH_MASK) {
344 case OBJ_SEARCH_OBJECT:
346 key = object->callbacks.name;
352 return ast_str_hash(key);
355 /*! \brief Comparator function for sorcery wizards */
356 static int sorcery_wizard_cmp(void *obj, void *arg, int flags)
358 const struct ast_sorcery_internal_wizard *object_left = obj;
359 const struct ast_sorcery_internal_wizard *object_right = arg;
360 const char *right_key = arg;
363 switch (flags & OBJ_SEARCH_MASK) {
364 case OBJ_SEARCH_OBJECT:
365 right_key = object_right->callbacks.name;
368 cmp = strcmp(object_left->callbacks.name, right_key);
370 case OBJ_SEARCH_PARTIAL_KEY:
371 cmp = strncmp(object_left->callbacks.name, right_key, strlen(right_key));
383 /*! \brief Hashing function for sorcery wizards */
384 static int object_type_field_hash(const void *obj, const int flags)
386 const struct ast_sorcery_object_field *object_field;
389 switch (flags & OBJ_SEARCH_MASK) {
393 case OBJ_SEARCH_OBJECT:
395 key = object_field->name;
401 return ast_str_hash(key);
404 static int object_type_field_cmp(void *obj, void *arg, int flags)
406 const struct ast_sorcery_object_field *field_left = obj;
407 const struct ast_sorcery_object_field *field_right = arg;
408 const char *right_key = arg;
411 switch (flags & OBJ_SEARCH_MASK) {
412 case OBJ_SEARCH_OBJECT:
413 right_key = field_right->name;
416 cmp = strcmp(field_left->name, right_key);
418 case OBJ_SEARCH_PARTIAL_KEY:
419 cmp = strncmp(field_left->name, right_key, strlen(right_key));
431 /*! \brief Cleanup function for graceful shutdowns */
432 static void sorcery_cleanup(void)
434 ast_threadpool_shutdown(threadpool);
436 ao2_cleanup(wizards);
438 ao2_cleanup(observers);
440 ao2_cleanup(instances);
444 /*! \brief Compare function for sorcery instances */
445 static int sorcery_instance_cmp(void *obj, void *arg, int flags)
447 const struct ast_sorcery *object_left = obj;
448 const struct ast_sorcery *object_right = arg;
449 const char *right_key = arg;
452 switch (flags & OBJ_SEARCH_MASK) {
453 case OBJ_SEARCH_OBJECT:
454 right_key = object_right->module_name;
457 cmp = strcmp(object_left->module_name, right_key);
459 case OBJ_SEARCH_PARTIAL_KEY:
460 cmp = strncmp(object_left->module_name, right_key, strlen(right_key));
472 /*! \brief Hashing function for sorcery instances */
473 static int sorcery_instance_hash(const void *obj, const int flags)
475 const struct ast_sorcery *object;
478 switch (flags & OBJ_SEARCH_MASK) {
482 case OBJ_SEARCH_OBJECT:
484 key = object->module_name;
490 return ast_str_hash(key);
493 int ast_sorcery_init(void)
495 struct ast_threadpool_options options = {
496 .version = AST_THREADPOOL_OPTIONS_VERSION,
502 ast_assert(wizards == NULL);
504 if (!(threadpool = ast_threadpool_create("Sorcery", NULL, &options))) {
509 if (!(wizards = ao2_container_alloc(WIZARD_BUCKETS, sorcery_wizard_hash, sorcery_wizard_cmp))) {
510 ast_threadpool_shutdown(threadpool);
514 observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL);
520 instances = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, INSTANCE_BUCKETS,
521 sorcery_instance_hash, sorcery_instance_cmp);
527 ast_register_cleanup(sorcery_cleanup);
532 static void sorcery_internal_wizard_destructor(void *obj)
534 struct ast_sorcery_internal_wizard *wizard = obj;
536 ao2_cleanup(wizard->observers);
539 int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module)
541 struct ast_sorcery_internal_wizard *wizard;
544 ast_assert(!ast_strlen_zero(interface->name));
548 if ((wizard = ao2_find(wizards, interface->name, OBJ_KEY | OBJ_NOLOCK))) {
549 ast_log(LOG_WARNING, "Attempted to register sorcery wizard '%s' twice\n",
554 if (!(wizard = ao2_alloc(sizeof(*wizard), sorcery_internal_wizard_destructor))) {
558 wizard->callbacks = *interface;
559 wizard->callbacks.module = module;
561 wizard->observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL);
562 if (!wizard->observers) {
566 ao2_link_flags(wizards, wizard, OBJ_NOLOCK);
569 ast_verb(2, "Sorcery registered wizard '%s'\n", interface->name);
571 NOTIFY_GLOBAL_OBSERVERS(observers, wizard_registered,
572 interface->name, interface);
581 int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
583 struct ast_sorcery_internal_wizard *wizard =
584 interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL;
587 NOTIFY_GLOBAL_OBSERVERS(observers, wizard_unregistering, wizard->callbacks.name, &wizard->callbacks);
588 ao2_unlink(wizards, wizard);
590 ast_verb(2, "Sorcery unregistered wizard '%s'\n", interface->name);
597 /*! \brief Internal callback function for removing a generic observer */
598 static int sorcery_generic_observer_remove(void *obj, void *arg, int flags)
600 const struct sorcery_global_observer *observer = obj;
602 return (observer->callbacks == arg) ? CMP_MATCH | CMP_STOP : 0;
605 int ast_sorcery_global_observer_add(const struct ast_sorcery_global_observer *callbacks)
607 struct sorcery_global_observer *cb;
609 cb = ao2_alloc(sizeof(*cb), NULL);
614 cb->callbacks = callbacks;
615 ao2_link(observers, cb);
621 void ast_sorcery_global_observer_remove(
622 const struct ast_sorcery_global_observer *callbacks)
624 ao2_callback(observers, OBJ_NODATA | OBJ_UNLINK, sorcery_generic_observer_remove, (void *)callbacks);
627 int ast_sorcery_instance_observer_add(struct ast_sorcery *sorcery,
628 const struct ast_sorcery_instance_observer *callbacks)
630 struct sorcery_instance_observer *cb;
632 cb = ao2_alloc(sizeof(*cb), NULL);
637 cb->callbacks = callbacks;
638 ao2_link(sorcery->observers, cb);
644 void ast_sorcery_instance_observer_remove(struct ast_sorcery *sorcery,
645 const struct ast_sorcery_instance_observer *callbacks)
647 ao2_callback(sorcery->observers, OBJ_NODATA | OBJ_UNLINK, sorcery_generic_observer_remove, (void *)callbacks);
650 int ast_sorcery_wizard_observer_add(struct ast_sorcery_wizard *interface,
651 const struct ast_sorcery_wizard_observer *callbacks)
653 RAII_VAR(struct ast_sorcery_internal_wizard *, wizard,
654 interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL,
658 struct sorcery_wizard_observer *cb;
660 cb = ao2_alloc(sizeof(*cb), NULL);
665 cb->callbacks = callbacks;
666 ao2_link(wizard->observers, cb);
675 void ast_sorcery_wizard_observer_remove(struct ast_sorcery_wizard *interface,
676 const struct ast_sorcery_wizard_observer *callbacks)
678 RAII_VAR(struct ast_sorcery_internal_wizard *, wizard,
679 interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL,
683 ao2_callback(wizard->observers, OBJ_NODATA | OBJ_UNLINK, sorcery_generic_observer_remove, (void *)callbacks);
687 /*! \brief Destructor called when sorcery structure is destroyed */
688 static void sorcery_destructor(void *obj)
690 struct ast_sorcery *sorcery = obj;
692 if (sorcery->observers) {
693 NOTIFY_GLOBAL_OBSERVERS(observers, instance_destroying, sorcery->module_name, sorcery);
695 ao2_cleanup(sorcery->observers);
696 ao2_cleanup(sorcery->types);
699 /*! \brief Hashing function for sorcery types */
700 static int sorcery_type_hash(const void *obj, const int flags)
702 const struct ast_sorcery_object_type *object;
705 switch (flags & OBJ_SEARCH_MASK) {
709 case OBJ_SEARCH_OBJECT:
717 return ast_str_hash(key);
720 /*! \brief Comparator function for sorcery types */
721 static int sorcery_type_cmp(void *obj, void *arg, int flags)
723 const struct ast_sorcery_object_type *object_left = obj;
724 const struct ast_sorcery_object_type *object_right = arg;
725 const char *right_key = arg;
728 switch (flags & OBJ_SEARCH_MASK) {
729 case OBJ_SEARCH_OBJECT:
730 right_key = object_right->name;
733 cmp = strcmp(object_left->name, right_key);
735 case OBJ_SEARCH_PARTIAL_KEY:
736 cmp = strncmp(object_left->name, right_key, strlen(right_key));
748 struct ast_sorcery *__ast_sorcery_open(const char *module_name)
750 struct ast_sorcery *sorcery;
752 ast_assert(module_name != NULL);
754 ao2_wrlock(instances);
755 if ((sorcery = ao2_find(instances, module_name, OBJ_SEARCH_KEY | OBJ_NOLOCK))) {
759 if (!(sorcery = ao2_alloc(sizeof(*sorcery) + strlen(module_name) + 1, sorcery_destructor))) {
763 if (!(sorcery->types = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, TYPE_BUCKETS, sorcery_type_hash, sorcery_type_cmp))) {
764 ao2_ref(sorcery, -1);
769 if (!(sorcery->observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL))) {
770 ao2_ref(sorcery, -1);
775 strcpy(sorcery->module_name, module_name); /* Safe */
777 if (__ast_sorcery_apply_config(sorcery, module_name, module_name) == AST_SORCERY_APPLY_FAIL) {
778 ast_log(LOG_ERROR, "Error attempting to apply configuration %s to sorcery.\n", module_name);
779 ao2_cleanup(sorcery);
784 ao2_link_flags(instances, sorcery, OBJ_NOLOCK);
786 NOTIFY_GLOBAL_OBSERVERS(observers, instance_created, module_name, sorcery);
789 ao2_unlock(instances);
793 /*! \brief Search function for sorcery instances */
794 struct ast_sorcery *ast_sorcery_retrieve_by_module_name(const char *module_name)
796 return ao2_find(instances, module_name, OBJ_SEARCH_KEY);
799 /*! \brief Destructor function for object types */
800 static void sorcery_object_type_destructor(void *obj)
802 struct ast_sorcery_object_type *object_type = obj;
804 AST_VECTOR_RW_WRLOCK(&object_type->wizards);
805 AST_VECTOR_CALLBACK_VOID(&object_type->wizards, ao2_cleanup);
806 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
807 AST_VECTOR_RW_FREE(&object_type->wizards);
808 ao2_cleanup(object_type->fields);
809 ao2_cleanup(object_type->observers);
811 if (object_type->info) {
812 aco_info_destroy(object_type->info);
813 ast_free(object_type->info);
816 ast_free(object_type->file);
818 ast_taskprocessor_unreference(object_type->serializer);
821 /*! \brief Internal function which allocates an object type structure */
822 static struct ast_sorcery_object_type *sorcery_object_type_alloc(const char *type, const char *module)
824 #define INITIAL_WIZARD_VECTOR_SIZE 5
825 struct ast_sorcery_object_type *object_type;
826 char uuid[AST_UUID_STR_LEN];
828 if (!(object_type = ao2_alloc(sizeof(*object_type), sorcery_object_type_destructor))) {
832 /* Order matters for object wizards */
833 if (AST_VECTOR_RW_INIT(&object_type->wizards, INITIAL_WIZARD_VECTOR_SIZE) != 0) {
834 ao2_ref(object_type, -1);
838 if (!(object_type->fields = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, OBJECT_FIELD_BUCKETS,
839 object_type_field_hash, object_type_field_cmp))) {
840 ao2_ref(object_type, -1);
844 if (!(object_type->observers = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, 1, NULL, NULL))) {
845 ao2_ref(object_type, -1);
849 if (!(object_type->info = ast_calloc(1, sizeof(*object_type->info) + 2 * sizeof(object_type->info->files[0])))) {
850 ao2_ref(object_type, -1);
854 if (!(object_type->file = ast_calloc(1, sizeof(*object_type->file) + 2 * sizeof(object_type->file->types[0])))) {
855 ao2_ref(object_type, -1);
859 if (!ast_uuid_generate_str(uuid, sizeof(uuid))) {
860 ao2_ref(object_type, -1);
864 if (!(object_type->serializer = ast_threadpool_serializer(uuid, threadpool))) {
865 ao2_ref(object_type, -1);
869 object_type->info->files[0] = object_type->file;
870 object_type->info->files[1] = NULL;
871 object_type->info->module = module;
873 ast_copy_string(object_type->name, type, sizeof(object_type->name));
878 /*! \brief Object wizard destructor */
879 static void sorcery_object_wizard_destructor(void *obj)
881 struct ast_sorcery_object_wizard *object_wizard = obj;
883 if (object_wizard->data && object_wizard->wizard->callbacks.close) {
884 object_wizard->wizard->callbacks.close(object_wizard->data);
887 if (object_wizard->wizard) {
888 ast_module_unref(object_wizard->wizard->callbacks.module);
891 ao2_cleanup(object_wizard->wizard);
894 /*! \brief Return the number of wizards mapped to an object type */
895 int ast_sorcery_get_wizard_mapping_count(struct ast_sorcery *sorcery,
898 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
904 return AST_VECTOR_SIZE(&object_type->wizards);
907 int ast_sorcery_get_wizard_mapping(struct ast_sorcery *sorcery,
908 const char *type, int index, struct ast_sorcery_wizard **wizard, void **data)
910 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
911 struct ast_sorcery_object_wizard *owizard;
917 if (index < 0 || index >= AST_VECTOR_SIZE(&object_type->wizards)) {
921 owizard = AST_VECTOR_GET(&object_type->wizards, index);
923 if (wizard != NULL) {
924 *wizard = &(owizard->wizard->callbacks);
925 ao2_bump(owizard->wizard);
931 *data = owizard->data;
937 /*! \brief Internal function removes a wizard mapping */
938 int __ast_sorcery_remove_wizard_mapping(struct ast_sorcery *sorcery,
939 const char *type, const char *module, const char *name)
941 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
948 AST_VECTOR_RW_WRLOCK(&object_type->wizards);
949 #define WIZARD_NAME_COMPARE(a, b) (strcmp((a)->wizard->callbacks.name, (b)) == 0)
950 res = AST_VECTOR_REMOVE_CMP_ORDERED(&object_type->wizards, name, WIZARD_NAME_COMPARE, ao2_cleanup);
951 #undef WIZARD_NAME_COMPARE
952 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
957 /*! \brief Internal function which creates an object type and inserts a wizard mapping */
958 enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sorcery *sorcery,
959 const char *type, const char *module, const char *name, const char *data,
960 unsigned int caching, int position)
962 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
963 RAII_VAR(struct ast_sorcery_internal_wizard *, wizard, ao2_find(wizards, name, OBJ_KEY), ao2_cleanup);
964 RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, ao2_alloc(sizeof(*object_wizard), sorcery_object_wizard_destructor), ao2_cleanup);
968 ast_log(LOG_ERROR, "Wizard '%s' could not be applied to object type '%s' as it was not found\n",
970 return AST_SORCERY_APPLY_FAIL;
971 } else if (!object_wizard) {
972 return AST_SORCERY_APPLY_FAIL;
976 if (!(object_type = sorcery_object_type_alloc(type, module))) {
977 return AST_SORCERY_APPLY_FAIL;
982 AST_VECTOR_RW_WRLOCK(&object_type->wizards);
984 struct ast_sorcery_object_wizard *found;
986 #define WIZARD_COMPARE(a, b) ((a)->wizard == (b))
987 found = AST_VECTOR_GET_CMP(&object_type->wizards, wizard, WIZARD_COMPARE);
988 #undef WIZARD_COMPARE
990 ast_debug(1, "Wizard %s already applied to object type %s\n",
991 wizard->callbacks.name, object_type->name);
992 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
993 return AST_SORCERY_APPLY_DUPLICATE;
997 ast_debug(5, "Calling wizard %s open callback on object type %s\n",
998 name, object_type->name);
999 if (wizard->callbacks.open && !(object_wizard->data = wizard->callbacks.open(data))) {
1000 ast_log(LOG_WARNING, "Wizard '%s' failed to open mapping for object type '%s' with data: %s\n",
1001 name, object_type->name, S_OR(data, ""));
1002 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
1003 return AST_SORCERY_APPLY_FAIL;
1006 ast_module_ref(wizard->callbacks.module);
1008 object_wizard->wizard = ao2_bump(wizard);
1009 object_wizard->caching = caching;
1011 if (position == AST_SORCERY_WIZARD_POSITION_LAST) {
1012 position = AST_VECTOR_SIZE(&object_type->wizards);
1015 if (AST_VECTOR_INSERT_AT(&object_type->wizards, position, object_wizard) != 0) {
1016 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
1017 return AST_SORCERY_APPLY_FAIL;
1019 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
1020 ao2_bump(object_wizard);
1023 ao2_link(sorcery->types, object_type);
1026 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, wizard_mapped,
1027 sorcery->module_name, sorcery, type, &wizard->callbacks, data, object_wizard->data);
1029 return AST_SORCERY_APPLY_SUCCESS;
1032 /*! \brief Internal function which creates an object type and adds a wizard mapping */
1033 enum ast_sorcery_apply_result __ast_sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery,
1034 const char *type, const char *module, const char *name, const char *data, unsigned int caching)
1036 return __ast_sorcery_insert_wizard_mapping(sorcery, type, module, name, data,
1037 caching, AST_SORCERY_WIZARD_POSITION_LAST);
1040 enum ast_sorcery_apply_result __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, const char *module)
1042 struct ast_flags flags = { 0 };
1043 struct ast_config *config = ast_config_load2("sorcery.conf", "sorcery", flags);
1044 struct ast_variable *mapping;
1045 int res = AST_SORCERY_APPLY_SUCCESS;
1048 return AST_SORCERY_APPLY_NO_CONFIGURATION;
1051 if (config == CONFIG_STATUS_FILEINVALID) {
1052 return AST_SORCERY_APPLY_FAIL;
1055 for (mapping = ast_variable_browse(config, name); mapping; mapping = mapping->next) {
1056 RAII_VAR(char *, mapping_name, ast_strdup(mapping->name), ast_free);
1057 RAII_VAR(char *, mapping_value, ast_strdup(mapping->value), ast_free);
1058 char *options = mapping_name;
1059 char *type = strsep(&options, "/");
1060 char *data = mapping_value;
1061 char *wizard = strsep(&data, ",");
1062 unsigned int caching = 0;
1064 /* If no object type or wizard exists just skip, nothing we can do */
1065 if (ast_strlen_zero(type) || ast_strlen_zero(wizard)) {
1069 /* If the wizard is configured as a cache treat it as such */
1070 if (!ast_strlen_zero(options) && strstr(options, "cache")) {
1074 /* Any error immediately causes us to stop */
1075 if (__ast_sorcery_apply_wizard_mapping(sorcery, type, module, wizard, data, caching) == AST_SORCERY_APPLY_FAIL) {
1076 res = AST_SORCERY_APPLY_FAIL;
1081 ast_config_destroy(config);
1086 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)
1088 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1090 /* Defaults can not be added if any existing mapping exists */
1092 return AST_SORCERY_APPLY_DEFAULT_UNNECESSARY;
1095 return __ast_sorcery_apply_wizard_mapping(sorcery, type, module, name, data, 0);
1098 static int sorcery_extended_config_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1100 return ast_sorcery_object_set_extended(obj, var->name, var->value);
1103 static int sorcery_extended_fields_handler(const void *obj, struct ast_variable **fields)
1105 const struct ast_sorcery_object_details *details = obj;
1107 if (details->object->extended) {
1108 *fields = ast_variables_dup(details->object->extended);
1116 int ast_sorcery_object_unregister(struct ast_sorcery *sorcery, const char *type)
1118 struct ast_sorcery_object_type *object_type;
1121 ao2_wrlock(sorcery->types);
1122 object_type = ao2_find(sorcery->types, type, OBJ_SEARCH_KEY | OBJ_NOLOCK);
1123 if (object_type && object_type->type.type == ACO_ITEM) {
1124 ao2_unlink_flags(sorcery->types, object_type, OBJ_NOLOCK);
1127 ao2_unlock(sorcery->types);
1129 /* XXX may need to add an instance unregister observer callback on success. */
1131 ao2_cleanup(object_type);
1135 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)
1137 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1139 if (!object_type || object_type->type.item_alloc) {
1143 object_type->type.name = object_type->name;
1144 object_type->type.type = ACO_ITEM;
1145 object_type->type.category = ".?";
1146 object_type->type.item_alloc = alloc;
1147 object_type->type.hidden = hidden;
1149 object_type->reloadable = reloadable;
1150 object_type->transform = transform;
1151 object_type->apply = apply;
1152 object_type->file->types[0] = &object_type->type;
1153 object_type->file->types[1] = NULL;
1155 if (aco_info_init(object_type->info)) {
1159 if (ast_sorcery_object_fields_register(sorcery, type, "^@", sorcery_extended_config_handler, sorcery_extended_fields_handler)) {
1163 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, object_type_registered,
1164 sorcery->module_name, sorcery, type);
1169 void ast_sorcery_object_set_copy_handler(struct ast_sorcery *sorcery, const char *type, sorcery_copy_handler copy)
1171 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1177 object_type->copy = copy;
1180 void ast_sorcery_object_set_diff_handler(struct ast_sorcery *sorcery, const char *type, sorcery_diff_handler diff)
1182 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1188 object_type->diff = diff;
1191 static void sorcery_object_field_destructor(void *obj)
1193 struct ast_sorcery_object_field *object_field = obj;
1195 if (object_field->name_regex) {
1196 regfree(object_field->name_regex);
1197 ast_free(object_field->name_regex);
1201 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)
1203 #define MAX_REGEX_ERROR_LEN 128
1204 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1205 RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, ao2_cleanup);
1208 if (!object_type || !object_type->type.item_alloc || !config_handler
1209 || !(object_field = ao2_alloc(sizeof(*object_field), sorcery_object_field_destructor))) {
1213 ast_copy_string(object_field->name, regex, sizeof(object_field->name));
1214 object_field->multiple_handler = sorcery_handler;
1216 if (!(object_field->name_regex = ast_calloc(1, sizeof(regex_t)))) {
1220 if ((rc = regcomp(object_field->name_regex, regex, REG_EXTENDED | REG_NOSUB))) {
1221 char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
1222 regerror(rc, object_field->name_regex, regerr, MAX_REGEX_ERROR_LEN);
1223 ast_log(LOG_ERROR, "Regular expression '%s' failed to compile: %s\n", regex, regerr);
1227 ao2_link(object_type->fields, object_field);
1228 __aco_option_register(object_type->info, regex, ACO_REGEX, object_type->file->types, "", OPT_CUSTOM_T, config_handler, 0, 1, 0);
1233 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,
1234 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, ...)
1236 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1237 RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, ao2_cleanup);
1241 if (!strcmp(type, "id") || !object_type || !object_type->type.item_alloc) {
1245 if (!sorcery_handler) {
1246 sorcery_handler = sorcery_field_default_handler(opt_type);
1249 if (!(object_field = ao2_alloc(sizeof(*object_field) + argc * sizeof(object_field->args[0]), NULL))) {
1253 ast_copy_string(object_field->name, name, sizeof(object_field->name));
1254 object_field->handler = sorcery_handler;
1255 object_field->multiple_handler = multiple_handler;
1257 va_start(args, argc);
1258 for (pos = 0; pos < argc; pos++) {
1259 object_field->args[pos] = va_arg(args, size_t);
1264 ao2_link(object_type->fields, object_field);
1267 /* TODO: Improve this hack */
1269 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc);
1270 } else if (argc == 1) {
1271 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
1272 object_field->args[0]);
1273 } else if (argc == 2) {
1274 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
1275 object_field->args[0], object_field->args[1]);
1276 } else if (argc == 3) {
1277 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
1278 object_field->args[0], object_field->args[1], object_field->args[2]);
1280 ast_assert(0); /* The hack... she does us no good for this */
1286 /*! \brief Retrieves whether or not the type is reloadable */
1287 static int sorcery_reloadable(const struct ast_sorcery *sorcery, const char *type)
1289 RAII_VAR(struct ast_sorcery_object_type *, object_type,
1290 ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1291 return object_type && object_type->reloadable;
1294 static int sorcery_wizard_load(void *obj, void *arg, int flags)
1296 struct ast_sorcery_object_wizard *wizard = obj;
1297 struct sorcery_load_details *details = arg;
1298 void (*load)(void *data, const struct ast_sorcery *sorcery, const char *type);
1300 load = !details->reload ? wizard->wizard->callbacks.load : wizard->wizard->callbacks.reload;
1303 NOTIFY_WIZARD_OBSERVERS(wizard->wizard->observers, wizard_loading,
1304 wizard->wizard->callbacks.name, &wizard->wizard->callbacks, details->type, details->reload);
1306 load(wizard->data, details->sorcery, details->type);
1308 NOTIFY_WIZARD_OBSERVERS(wizard->wizard->observers, wizard_loaded,
1309 wizard->wizard->callbacks.name, &wizard->wizard->callbacks, details->type, details->reload);
1315 /*! \brief Destructor for observer invocation */
1316 static void sorcery_observer_invocation_destroy(void *obj)
1318 struct sorcery_observer_invocation *invocation = obj;
1320 ao2_cleanup(invocation->object_type);
1321 ao2_cleanup(invocation->object);
1324 /*! \brief Allocator function for observer invocation */
1325 static struct sorcery_observer_invocation *sorcery_observer_invocation_alloc(struct ast_sorcery_object_type *object_type, void *object)
1327 struct sorcery_observer_invocation *invocation = ao2_alloc(sizeof(*invocation), sorcery_observer_invocation_destroy);
1333 ao2_ref(object_type, +1);
1334 invocation->object_type = object_type;
1337 ao2_ref(object, +1);
1338 invocation->object = object;
1344 /*! \brief Internal callback function which notifies an individual observer that an object type has been loaded */
1345 static int sorcery_observer_notify_loaded(void *obj, void *arg, int flags)
1347 const struct ast_sorcery_object_type_observer *observer = obj;
1349 if (observer->callbacks->loaded) {
1350 observer->callbacks->loaded(arg);
1356 /*! \brief Internal callback function which notifies observers that an object type has been loaded */
1357 static int sorcery_observers_notify_loaded(void *data)
1359 struct sorcery_observer_invocation *invocation = data;
1361 ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_loaded, invocation->object_type->name);
1362 ao2_cleanup(invocation);
1367 static int sorcery_object_load(void *obj, void *arg, int flags)
1369 struct ast_sorcery_object_type *type = obj;
1370 struct sorcery_load_details *details = arg;
1372 if (!type->type.item_alloc) {
1376 details->type = type->name;
1378 if (details->reload && !sorcery_reloadable(details->sorcery, details->type)) {
1379 ast_log(LOG_NOTICE, "Type '%s' is not reloadable, maintaining previous values\n",
1384 NOTIFY_INSTANCE_OBSERVERS(details->sorcery->observers, object_type_loading,
1385 details->sorcery->module_name, details->sorcery, type->name, details->reload);
1387 AST_VECTOR_RW_RDLOCK(&type->wizards);
1388 AST_VECTOR_CALLBACK(&type->wizards, sorcery_wizard_load, NULL, details, 0);
1389 AST_VECTOR_RW_UNLOCK(&type->wizards);
1391 NOTIFY_INSTANCE_OBSERVERS(details->sorcery->observers, object_type_loaded,
1392 details->sorcery->module_name, details->sorcery, type->name, details->reload);
1394 if (ao2_container_count(type->observers)) {
1395 struct sorcery_observer_invocation *invocation;
1397 invocation = sorcery_observer_invocation_alloc(type, NULL);
1399 && ast_taskprocessor_push(type->serializer, sorcery_observers_notify_loaded,
1401 ao2_cleanup(invocation);
1408 void ast_sorcery_load(const struct ast_sorcery *sorcery)
1410 struct sorcery_load_details details = {
1415 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loading,
1416 sorcery->module_name, sorcery, 0);
1418 ao2_callback(sorcery->types, OBJ_NODATA, sorcery_object_load, &details);
1420 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loaded,
1421 sorcery->module_name, sorcery, 0);
1424 void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type)
1426 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1427 struct sorcery_load_details details = {
1436 sorcery_object_load(object_type, &details, 0);
1439 void ast_sorcery_reload(const struct ast_sorcery *sorcery)
1441 struct sorcery_load_details details = {
1446 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loading,
1447 sorcery->module_name, sorcery, 1);
1449 ao2_callback(sorcery->types, OBJ_NODATA, sorcery_object_load, &details);
1451 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loaded,
1452 sorcery->module_name, sorcery, 1);
1456 void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
1458 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1459 struct sorcery_load_details details = {
1468 sorcery_object_load(object_type, &details, 0);
1471 void ast_sorcery_ref(struct ast_sorcery *sorcery)
1473 ao2_ref(sorcery, +1);
1476 static struct ast_variable *get_single_field_as_var_list(const void *object, struct ast_sorcery_object_field *object_field)
1478 struct ast_variable *tmp = NULL;
1481 if (!object_field->handler) {
1485 if (!(object_field->handler(object, object_field->args, &buf))) {
1486 tmp = ast_variable_new(object_field->name, S_OR(buf, ""), "");
1493 static struct ast_variable *get_multiple_fields_as_var_list(const void *object, struct ast_sorcery_object_field *object_field)
1495 struct ast_variable *tmp = NULL;
1497 if (!object_field->multiple_handler) {
1501 if (object_field->multiple_handler(object, &tmp)) {
1502 ast_variables_destroy(tmp);
1509 struct ast_variable *ast_sorcery_objectset_create2(const struct ast_sorcery *sorcery,
1510 const void *object, enum ast_sorcery_field_handler_flags flags)
1512 const struct ast_sorcery_object_details *details = object;
1513 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1514 struct ao2_iterator i;
1515 struct ast_sorcery_object_field *object_field;
1516 struct ast_variable *head = NULL;
1517 struct ast_variable *tail = NULL;
1523 i = ao2_iterator_init(object_type->fields, 0);
1525 for (; (object_field = ao2_iterator_next(&i)); ao2_ref(object_field, -1)) {
1526 struct ast_variable *tmp;
1529 case AST_HANDLER_PREFER_LIST:
1530 if ((tmp = get_multiple_fields_as_var_list(object, object_field)) ||
1531 (tmp = get_single_field_as_var_list(object, object_field))) {
1535 case AST_HANDLER_PREFER_STRING:
1536 if ((tmp = get_single_field_as_var_list(object, object_field)) ||
1537 (tmp = get_multiple_fields_as_var_list(object, object_field))) {
1541 case AST_HANDLER_ONLY_LIST:
1542 if ((tmp = get_multiple_fields_as_var_list(object, object_field))) {
1546 case AST_HANDLER_ONLY_STRING:
1547 if ((tmp = get_single_field_as_var_list(object, object_field))) {
1555 tail = ast_variable_list_append_hint(&head, tail, tmp);
1558 ao2_iterator_destroy(&i);
1563 struct ast_json *ast_sorcery_objectset_json_create(const struct ast_sorcery *sorcery, const void *object)
1565 const struct ast_sorcery_object_details *details = object;
1566 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1567 struct ao2_iterator i;
1568 struct ast_sorcery_object_field *object_field;
1569 struct ast_json *json = ast_json_object_create();
1572 if (!object_type || !json) {
1576 i = ao2_iterator_init(object_type->fields, 0);
1578 for (; !res && (object_field = ao2_iterator_next(&i)); ao2_ref(object_field, -1)) {
1579 if (object_field->multiple_handler) {
1580 struct ast_variable *tmp = NULL;
1581 struct ast_variable *field;
1583 if ((res = object_field->multiple_handler(object, &tmp))) {
1584 ast_variables_destroy(tmp);
1585 ao2_ref(object_field, -1);
1589 for (field = tmp; field; field = field->next) {
1590 struct ast_json *value = ast_json_string_create(field->value);
1592 if (!value || ast_json_object_set(json, field->name, value)) {
1598 ast_variables_destroy(tmp);
1599 } else if (object_field->handler) {
1601 struct ast_json *value = NULL;
1603 if ((res = object_field->handler(object, object_field->args, &buf))
1604 || !(value = ast_json_string_create(buf))
1605 || ast_json_object_set(json, object_field->name, value)) {
1615 ao2_iterator_destroy(&i);
1617 /* If any error occurs we destroy the JSON object so a partial objectset is not returned */
1619 ast_json_unref(json);
1626 int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object, struct ast_variable *objectset)
1628 const struct ast_sorcery_object_details *details = object;
1629 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1630 RAII_VAR(struct ast_variable *, transformed, NULL, ast_variables_destroy);
1631 struct ast_variable *field;
1638 if (object_type->transform && (transformed = object_type->transform(objectset))) {
1639 field = transformed;
1644 for (; field; field = field->next) {
1645 if ((res = aco_process_var(&object_type->type, details->object->id, field, object))) {
1650 if (!res && object_type->apply) {
1651 res = object_type->apply(sorcery, object);
1657 int ast_sorcery_changeset_create(const struct ast_variable *original, const struct ast_variable *modified, struct ast_variable **changes)
1659 const struct ast_variable *field;
1664 /* Unless the ast_variable list changes when examined... it can't differ from itself */
1665 if (original == modified) {
1669 for (field = modified; field; field = field->next) {
1670 const char *old_value = ast_variable_find_in_list(original, field->name);
1672 if (!old_value || strcmp(old_value, field->value)) {
1673 struct ast_variable *tmp;
1675 if (!(tmp = ast_variable_new(field->name, field->value, ""))) {
1680 tmp->next = *changes;
1685 /* If an error occurred do not return a partial changeset */
1687 ast_variables_destroy(*changes);
1694 static void sorcery_object_destructor(void *object)
1696 struct ast_sorcery_object_details *details = object;
1698 if (details->object->destructor) {
1699 details->object->destructor(object);
1702 ast_variables_destroy(details->object->extended);
1703 ast_free(details->object->id);
1706 void *ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
1708 void *object = ao2_alloc_options(size + sizeof(struct ast_sorcery_object), sorcery_object_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
1709 struct ast_sorcery_object_details *details = object;
1715 details->object = object + size;
1716 details->object->destructor = destructor;
1721 void *ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
1723 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1724 struct ast_sorcery_object_details *details;
1726 if (!object_type || !object_type->type.item_alloc ||
1727 !(details = object_type->type.item_alloc(id))) {
1731 if (ast_strlen_zero(id)) {
1732 char uuid[AST_UUID_STR_LEN];
1734 ast_uuid_generate_str(uuid, sizeof(uuid));
1735 details->object->id = ast_strdup(uuid);
1737 details->object->id = ast_strdup(id);
1740 details->object->created = ast_tvnow();
1741 ast_copy_string(details->object->type, type, sizeof(details->object->type));
1743 if (aco_set_defaults(&object_type->type, id, details)) {
1744 ao2_ref(details, -1);
1751 void *ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
1753 const struct ast_sorcery_object_details *details = object;
1754 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1755 struct ast_sorcery_object_details *copy = ast_sorcery_alloc(sorcery, details->object->type, details->object->id);
1756 RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy);
1761 } else if (object_type->copy) {
1762 res = object_type->copy(object, copy);
1763 } else if ((objectset = ast_sorcery_objectset_create(sorcery, object))) {
1764 res = ast_sorcery_objectset_apply(sorcery, copy, objectset);
1766 /* No native copy available and could not create an objectset, this copy has failed */
1778 int ast_sorcery_diff(const struct ast_sorcery *sorcery, const void *original, const void *modified, struct ast_variable **changes)
1780 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, ast_sorcery_object_get_type(original), OBJ_KEY), ao2_cleanup);
1784 if (strcmp(ast_sorcery_object_get_type(original), ast_sorcery_object_get_type(modified))) {
1788 if (original == modified) {
1790 } else if (!object_type->diff) {
1791 RAII_VAR(struct ast_variable *, objectset1, NULL, ast_variables_destroy);
1792 RAII_VAR(struct ast_variable *, objectset2, NULL, ast_variables_destroy);
1794 objectset1 = ast_sorcery_objectset_create(sorcery, original);
1795 objectset2 = ast_sorcery_objectset_create(sorcery, modified);
1797 return ast_sorcery_changeset_create(objectset1, objectset2, changes);
1799 return object_type->diff(original, modified, changes);
1803 /*! \brief Structure used when calling create, update, or delete */
1804 struct sorcery_details {
1805 /*! \brief Pointer to the sorcery instance */
1806 const struct ast_sorcery *sorcery;
1807 /*! \brief Pointer to the object itself */
1811 /*! \brief Internal function used to create an object in caching wizards */
1812 static int sorcery_cache_create(void *obj, void *arg, int flags)
1814 const struct ast_sorcery_object_wizard *object_wizard = obj;
1815 const struct sorcery_details *details = arg;
1817 if (!object_wizard->caching || !object_wizard->wizard->callbacks.create) {
1821 object_wizard->wizard->callbacks.create(details->sorcery, object_wizard->data, details->obj);
1826 void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
1828 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1829 void *object = NULL;
1831 unsigned int cached = 0;
1833 if (!object_type || ast_strlen_zero(id)) {
1837 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
1838 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
1839 struct ast_sorcery_object_wizard *wizard =
1840 AST_VECTOR_GET(&object_type->wizards, i);
1842 if (wizard->wizard->callbacks.retrieve_id &&
1843 !(object = wizard->wizard->callbacks.retrieve_id(sorcery, wizard->data, object_type->name, id))) {
1847 cached = wizard->caching;
1851 if (!cached && object) {
1852 struct sorcery_details sdetails = {
1857 AST_VECTOR_CALLBACK(&object_type->wizards, sorcery_cache_create, NULL, &sdetails, 0);
1859 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
1864 void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
1866 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1867 void *object = NULL;
1869 unsigned int cached = 0;
1875 /* If returning multiple objects create a container to store them in */
1876 if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
1877 if (!(object = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
1882 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
1883 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
1884 struct ast_sorcery_object_wizard *wizard =
1885 AST_VECTOR_GET(&object_type->wizards, i);
1887 if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
1888 if (wizard->wizard->callbacks.retrieve_multiple) {
1889 wizard->wizard->callbacks.retrieve_multiple(sorcery, wizard->data, object_type->name, object, fields);
1891 } else if (fields && wizard->wizard->callbacks.retrieve_fields) {
1892 if (wizard->wizard->callbacks.retrieve_fields) {
1893 object = wizard->wizard->callbacks.retrieve_fields(sorcery, wizard->data, object_type->name, fields);
1897 if ((flags & AST_RETRIEVE_FLAG_MULTIPLE) || !object) {
1901 cached = wizard->caching;
1906 /* If we are returning a single object and it came from a non-cache source create it in any caches */
1907 if (!(flags & AST_RETRIEVE_FLAG_MULTIPLE) && !cached && object) {
1908 AST_VECTOR_CALLBACK(&object_type->wizards, sorcery_cache_create, NULL, object, 0);
1910 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
1915 struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex)
1917 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
1918 struct ao2_container *objects;
1921 if (!object_type || !(objects = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
1925 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
1926 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
1927 struct ast_sorcery_object_wizard *wizard =
1928 AST_VECTOR_GET(&object_type->wizards, i);
1930 if (!wizard->wizard->callbacks.retrieve_regex) {
1934 wizard->wizard->callbacks.retrieve_regex(sorcery, wizard->data, object_type->name, objects, regex);
1936 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
1941 /*! \brief Internal function which returns if the wizard has created the object */
1942 static int sorcery_wizard_create(void *obj, void *arg, int flags)
1944 const struct ast_sorcery_object_wizard *object_wizard = obj;
1945 const struct sorcery_details *details = arg;
1947 if (!object_wizard->wizard->callbacks.create) {
1948 ast_debug(5, "Sorcery wizard '%s' does not support creation\n", object_wizard->wizard->callbacks.name);
1951 return (!object_wizard->caching && !object_wizard->wizard->callbacks.create(details->sorcery, object_wizard->data, details->obj)) ? CMP_MATCH | CMP_STOP : 0;
1954 /*! \brief Internal callback function which notifies an individual observer that an object has been created */
1955 static int sorcery_observer_notify_create(void *obj, void *arg, int flags)
1957 const struct ast_sorcery_object_type_observer *observer = obj;
1959 if (observer->callbacks->created) {
1960 observer->callbacks->created(arg);
1966 /*! \brief Internal callback function which notifies observers that an object has been created */
1967 static int sorcery_observers_notify_create(void *data)
1969 struct sorcery_observer_invocation *invocation = data;
1971 ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_create, invocation->object);
1972 ao2_cleanup(invocation);
1977 int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
1979 const struct ast_sorcery_object_details *details = object;
1980 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1981 struct ast_sorcery_object_wizard *object_wizard = NULL;
1982 struct ast_sorcery_object_wizard *found_wizard;
1984 struct sorcery_details sdetails = {
1993 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
1994 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
1995 found_wizard = AST_VECTOR_GET(&object_type->wizards, i);
1996 if (sorcery_wizard_create(found_wizard, &sdetails, 0) == (CMP_MATCH | CMP_STOP)) {
1997 object_wizard = found_wizard;
1998 if(ao2_container_count(object_type->observers)) {
1999 struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
2001 if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_create, invocation)) {
2002 ao2_cleanup(invocation);
2007 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
2009 return object_wizard ? 0 : -1;
2012 /*! \brief Internal callback function which notifies an individual observer that an object has been updated */
2013 static int sorcery_observer_notify_update(void *obj, void *arg, int flags)
2015 const struct ast_sorcery_object_type_observer *observer = obj;
2017 if (observer->callbacks->updated) {
2018 observer->callbacks->updated(arg);
2024 /*! \brief Internal callback function which notifies observers that an object has been updated */
2025 static int sorcery_observers_notify_update(void *data)
2027 struct sorcery_observer_invocation *invocation = data;
2029 ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_update, invocation->object);
2030 ao2_cleanup(invocation);
2035 /*! \brief Internal function which returns if a wizard has updated the object */
2036 static int sorcery_wizard_update(void *obj, void *arg, int flags)
2038 const struct ast_sorcery_object_wizard *object_wizard = obj;
2039 const struct sorcery_details *details = arg;
2041 if (!object_wizard->wizard->callbacks.update) {
2042 ast_debug(5, "Sorcery wizard '%s' does not support updating\n", object_wizard->wizard->callbacks.name);
2046 return (!object_wizard->wizard->callbacks.update(details->sorcery, object_wizard->data, details->obj) &&
2047 !object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0;
2050 int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
2052 const struct ast_sorcery_object_details *details = object;
2053 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
2054 struct ast_sorcery_object_wizard *object_wizard = NULL;
2055 struct ast_sorcery_object_wizard *found_wizard;
2057 struct sorcery_details sdetails = {
2066 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
2067 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
2068 found_wizard = AST_VECTOR_GET(&object_type->wizards, i);
2069 if (sorcery_wizard_update(found_wizard, &sdetails, 0) == (CMP_MATCH | CMP_STOP)) {
2070 object_wizard = found_wizard;
2071 if (ao2_container_count(object_type->observers)) {
2072 struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
2074 if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_update, invocation)) {
2075 ao2_cleanup(invocation);
2080 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
2082 return object_wizard ? 0 : -1;
2085 /*! \brief Internal callback function which notifies an individual observer that an object has been deleted */
2086 static int sorcery_observer_notify_delete(void *obj, void *arg, int flags)
2088 const struct ast_sorcery_object_type_observer *observer = obj;
2090 if (observer->callbacks->deleted) {
2091 observer->callbacks->deleted(arg);
2097 /*! \brief Internal callback function which notifies observers that an object has been deleted */
2098 static int sorcery_observers_notify_delete(void *data)
2100 struct sorcery_observer_invocation *invocation = data;
2102 ao2_callback(invocation->object_type->observers, OBJ_NODATA, sorcery_observer_notify_delete, invocation->object);
2103 ao2_cleanup(invocation);
2108 /*! \brief Internal function which returns if a wizard has deleted the object */
2109 static int sorcery_wizard_delete(void *obj, void *arg, int flags)
2111 const struct ast_sorcery_object_wizard *object_wizard = obj;
2112 const struct sorcery_details *details = arg;
2114 if (!object_wizard->wizard->callbacks.delete) {
2115 ast_debug(5, "Sorcery wizard '%s' does not support deletion\n", object_wizard->wizard->callbacks.name);
2119 return (!object_wizard->wizard->callbacks.delete(details->sorcery, object_wizard->data, details->obj) &&
2120 !object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0;
2123 int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
2125 const struct ast_sorcery_object_details *details = object;
2126 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
2127 struct ast_sorcery_object_wizard *object_wizard = NULL;
2128 struct ast_sorcery_object_wizard *found_wizard;
2130 struct sorcery_details sdetails = {
2139 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
2140 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
2141 found_wizard = AST_VECTOR_GET(&object_type->wizards, i);
2142 if (sorcery_wizard_delete(found_wizard, &sdetails, 0) == (CMP_MATCH | CMP_STOP)) {
2143 object_wizard = found_wizard;
2144 if (ao2_container_count(object_type->observers)) {
2145 struct sorcery_observer_invocation *invocation = sorcery_observer_invocation_alloc(object_type, object);
2147 if (invocation && ast_taskprocessor_push(object_type->serializer, sorcery_observers_notify_delete, invocation)) {
2148 ao2_cleanup(invocation);
2153 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
2155 return object_wizard ? 0 : -1;
2158 int ast_sorcery_is_stale(const struct ast_sorcery *sorcery, void *object)
2160 const struct ast_sorcery_object_details *details = object;
2161 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
2162 struct ast_sorcery_object_wizard *found_wizard;
2170 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
2171 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
2172 found_wizard = AST_VECTOR_GET(&object_type->wizards, i);
2174 if (found_wizard->wizard->callbacks.is_stale) {
2175 res |= found_wizard->wizard->callbacks.is_stale(sorcery, found_wizard->data, object);
2176 ast_debug(5, "After calling wizard '%s', object '%s' is %s\n",
2177 found_wizard->wizard->callbacks.name,
2178 ast_sorcery_object_get_id(object),
2179 res ? "stale" : "not stale");
2182 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
2187 void ast_sorcery_unref(struct ast_sorcery *sorcery)
2190 /* One ref for what we just released, the other for the instances container. */
2191 ao2_wrlock(instances);
2192 if (ao2_ref(sorcery, -1) == 2) {
2193 ao2_unlink_flags(instances, sorcery, OBJ_NOLOCK);
2195 ao2_unlock(instances);
2199 const char *ast_sorcery_object_get_id(const void *object)
2201 const struct ast_sorcery_object_details *details = object;
2202 return details->object->id;
2205 const struct timeval ast_sorcery_object_get_created(const void *object)
2207 const struct ast_sorcery_object_details *details = object;
2208 return details->object->created;
2211 const char *ast_sorcery_object_get_type(const void *object)
2213 const struct ast_sorcery_object_details *details = object;
2214 return details->object->type;
2217 const char *ast_sorcery_object_get_extended(const void *object, const char *name)
2219 const struct ast_sorcery_object_details *details = object;
2220 struct ast_variable *field;
2222 for (field = details->object->extended; field; field = field->next) {
2223 if (!strcmp(field->name + 1, name)) {
2224 return field->value;
2231 int ast_sorcery_object_set_extended(const void *object, const char *name, const char *value)
2233 RAII_VAR(struct ast_variable *, field, NULL, ast_variables_destroy);
2234 struct ast_variable *extended = ast_variable_new(name, value, ""), *previous = NULL;
2235 const struct ast_sorcery_object_details *details = object;
2241 for (field = details->object->extended; field; previous = field, field = field->next) {
2242 if (!strcmp(field->name, name)) {
2244 previous->next = field->next;
2246 details->object->extended = field->next;
2253 extended->next = details->object->extended;
2254 details->object->extended = extended;
2259 int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
2261 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
2262 struct ast_sorcery_object_type_observer *observer;
2265 if (!object_type || !callbacks) {
2269 if (!(observer = ao2_alloc(sizeof(*observer), NULL))) {
2273 observer->callbacks = callbacks;
2275 if (!ao2_link(object_type->observers, observer)) {
2278 ao2_ref(observer, -1);
2283 /*! \brief Internal callback function for removing an observer */
2284 static int sorcery_observer_remove(void *obj, void *arg, int flags)
2286 const struct ast_sorcery_object_type_observer *observer = obj;
2288 return (observer->callbacks == arg) ? CMP_MATCH | CMP_STOP : 0;
2291 void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
2293 RAII_VAR(struct ast_sorcery_object_type *, object_type, NULL, ao2_cleanup);
2294 struct ast_sorcery_observer *cbs = (struct ast_sorcery_observer *) callbacks;/* Remove const for traversal. */
2299 object_type = ao2_find(sorcery->types, type, OBJ_KEY);
2304 ao2_callback(object_type->observers, OBJ_NODATA | OBJ_UNLINK,
2305 sorcery_observer_remove, cbs);
2308 int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
2310 const char *right_key = arg;
2313 switch (flags & OBJ_SEARCH_MASK) {
2314 case OBJ_SEARCH_OBJECT:
2315 right_key = ast_sorcery_object_get_id(arg);
2317 case OBJ_SEARCH_KEY:
2318 cmp = strcmp(ast_sorcery_object_get_id(obj), right_key);
2320 case OBJ_SEARCH_PARTIAL_KEY:
2321 cmp = strncmp(ast_sorcery_object_get_id(obj), right_key, strlen(right_key));
2330 int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
2332 const char *right_key = arg;
2335 switch (flags & OBJ_SEARCH_MASK) {
2336 case OBJ_SEARCH_OBJECT:
2337 right_key = ast_sorcery_object_get_id(arg);
2339 case OBJ_SEARCH_KEY:
2340 if (strcmp(ast_sorcery_object_get_id(obj), right_key) == 0) {
2341 cmp = CMP_MATCH | CMP_STOP;
2344 case OBJ_SEARCH_PARTIAL_KEY:
2345 if (strncmp(ast_sorcery_object_get_id(obj), right_key, strlen(right_key)) == 0) {
2356 int ast_sorcery_object_id_hash(const void *obj, int flags) {
2357 if (flags & OBJ_SEARCH_OBJECT) {
2358 return ast_str_hash(ast_sorcery_object_get_id(obj));
2359 } else if (flags & OBJ_SEARCH_KEY) {
2360 return ast_str_hash(obj);
2365 struct ast_sorcery_object_type *ast_sorcery_get_object_type(const struct ast_sorcery *sorcery,
2368 return ao2_find(sorcery->types, type, OBJ_SEARCH_KEY);
2371 static int is_registered_cb(void *obj, void *arg, int flags)
2373 struct ast_sorcery_object_field *object_field = obj;
2377 if (object_field->name_regex
2378 && !regexec(object_field->name_regex, name, 0, NULL, 0)) {
2379 rc = CMP_MATCH | CMP_STOP;
2385 int ast_sorcery_is_object_field_registered(const struct ast_sorcery_object_type *object_type,
2386 const char *field_name)
2388 struct ast_sorcery_object_field *object_field;
2391 ast_assert(object_type != NULL);
2393 object_field = ao2_find(object_type->fields, field_name, OBJ_SEARCH_KEY);
2395 if (!object_field) {
2396 object_field = ao2_callback(object_type->fields, 0, is_registered_cb, (char *)field_name);
2399 if (!object_field) {
2403 ao2_cleanup(object_field);
2407 const char *ast_sorcery_get_module(const struct ast_sorcery *sorcery)
2409 return sorcery->module_name;