mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-02 19:16:15 +00:00
sorcery.c: Sorcery enhancements for wizard management
Added ability to specifiy a wizard is read-only when applying it to a specific object type. This allows you to specify create, update and delete callbacks for the wizard but limit which object types can use them. Added the ability to allow an object type to have multiple wizards of the same type. This is indicated when a wizard is added to a specific object type. Added 3 new sorcery wizard functions: * ast_sorcery_object_type_insert_wizard which does the same thing as the existing ast_sorcery_insert_wizard_mapping function but accepts the new read-only and allot-duplicates flags and also returns the ast_sorcery_wizard structure used and it's internal data structure. This allows immediate use of the wizard's callbacks without having to register a "wizard mapped" observer. * ast_sorcery_object_type_apply_wizard which does the same thing as the existing ast_sorcery_apply_wizard_mapping function but has the added capabilities of ast_sorcery_object_type_insert_wizard. * ast_sorcery_object_type_remove_wizard which removes a wizard matching both its name and its original argument string. * The original logic in __ast_sorcery_insert_wizard_mapping was moved to __ast_sorcery_object_type_insert_wizard and enhanced for the new capabilities, then __ast_sorcery_insert_wizard_mapping was refactored to just call __ast_sorcery_insert_wizard_mapping. * Added a unit test to test_sorcery.c to test the read-only capability. Change-Id: I40f35840252e4313d99e11dbd80e270a3aa10605
This commit is contained in:
126
main/sorcery.c
126
main/sorcery.c
@@ -109,6 +109,15 @@ struct ast_sorcery_object_wizard {
|
||||
|
||||
/*! \brief Wizard is acting as an object cache */
|
||||
unsigned int caching:1;
|
||||
|
||||
/*! \brief Wizard is read_only */
|
||||
unsigned int read_only:1;
|
||||
|
||||
/*! \brief Wizard allows others of the same type */
|
||||
unsigned int allow_duplicates:1;
|
||||
|
||||
/*! \brief Wizard arguments */
|
||||
char wizard_args[0];
|
||||
};
|
||||
|
||||
/*! \brief Interface for a sorcery object type wizards */
|
||||
@@ -802,6 +811,35 @@ int ast_sorcery_get_wizard_mapping(struct ast_sorcery *sorcery,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __ast_sorcery_object_type_remove_wizard(struct ast_sorcery *sorcery,
|
||||
const char *object_type_name, const char *module, const char *wizard_type_name,
|
||||
const char *wizard_args)
|
||||
{
|
||||
RAII_VAR(struct ast_sorcery_object_type *, object_type,
|
||||
ao2_find(sorcery->types, object_type_name, OBJ_SEARCH_KEY), ao2_cleanup);
|
||||
int res = -1;
|
||||
int i;
|
||||
|
||||
if (!object_type) {
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_VECTOR_RW_WRLOCK(&object_type->wizards);
|
||||
for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
|
||||
struct ast_sorcery_object_wizard *wizard = AST_VECTOR_GET(&object_type->wizards, i);
|
||||
|
||||
if (strcmp(wizard->wizard->callbacks.name, wizard_type_name) == 0
|
||||
&& strcmp(S_OR(wizard->wizard_args, ""), S_OR(wizard_args, "")) == 0) {
|
||||
ao2_cleanup(AST_VECTOR_REMOVE_ORDERED(&object_type->wizards, i));
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
AST_VECTOR_RW_UNLOCK(&object_type->wizards);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief Internal function removes a wizard mapping */
|
||||
int __ast_sorcery_remove_wizard_mapping(struct ast_sorcery *sorcery,
|
||||
const char *type, const char *module, const char *name)
|
||||
@@ -822,29 +860,35 @@ int __ast_sorcery_remove_wizard_mapping(struct ast_sorcery *sorcery,
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief Internal function which creates an object type and inserts a wizard mapping */
|
||||
enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sorcery *sorcery,
|
||||
const char *type, const char *module, const char *name, const char *data,
|
||||
unsigned int caching, int position)
|
||||
enum ast_sorcery_apply_result __ast_sorcery_object_type_insert_wizard(struct ast_sorcery *sorcery,
|
||||
const char *object_type_name, const char *module, const char *wizard_type_name,
|
||||
const char *wizard_args, enum ast_sorcery_wizard_apply_flags flags, int position,
|
||||
struct ast_sorcery_wizard **wizard, void **wizard_data)
|
||||
{
|
||||
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
|
||||
RAII_VAR(struct ast_sorcery_internal_wizard *, wizard, ao2_find(wizards, name, OBJ_KEY), ao2_cleanup);
|
||||
RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, ao2_alloc(sizeof(*object_wizard), sorcery_object_wizard_destructor), ao2_cleanup);
|
||||
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, object_type_name, OBJ_KEY), ao2_cleanup);
|
||||
RAII_VAR(struct ast_sorcery_internal_wizard *, internal_wizard, ao2_find(wizards, wizard_type_name, OBJ_KEY), ao2_cleanup);
|
||||
RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
|
||||
int created = 0;
|
||||
|
||||
object_wizard = ao2_alloc(sizeof(*object_wizard)
|
||||
+ (ast_strlen_zero(wizard_args) ? 0 : strlen(wizard_args) + 1),
|
||||
sorcery_object_wizard_destructor);
|
||||
|
||||
if (!object_wizard) {
|
||||
return AST_SORCERY_APPLY_FAIL;
|
||||
}
|
||||
|
||||
if (!wizard || wizard->callbacks.module != ast_module_running_ref(wizard->callbacks.module)) {
|
||||
ast_log(LOG_ERROR, "Wizard '%s' could not be applied to object type '%s' as it was not found\n",
|
||||
name, type);
|
||||
if (!internal_wizard
|
||||
|| internal_wizard->callbacks.module != ast_module_running_ref(internal_wizard->callbacks.module)) {
|
||||
ast_log(LOG_ERROR,
|
||||
"Wizard '%s' could not be applied to object type '%s' as it was not found\n",
|
||||
wizard_type_name, object_type_name);
|
||||
return AST_SORCERY_APPLY_FAIL;
|
||||
}
|
||||
|
||||
if (!object_type) {
|
||||
if (!(object_type = sorcery_object_type_alloc(type, module))) {
|
||||
ast_module_unref(wizard->callbacks.module);
|
||||
if (!(object_type = sorcery_object_type_alloc(object_type_name, module))) {
|
||||
ast_module_unref(internal_wizard->callbacks.module);
|
||||
return AST_SORCERY_APPLY_FAIL;
|
||||
}
|
||||
created = 1;
|
||||
@@ -855,29 +899,34 @@ enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sor
|
||||
struct ast_sorcery_object_wizard *found;
|
||||
|
||||
#define WIZARD_COMPARE(a, b) ((a)->wizard == (b))
|
||||
found = AST_VECTOR_GET_CMP(&object_type->wizards, wizard, WIZARD_COMPARE);
|
||||
found = AST_VECTOR_GET_CMP(&object_type->wizards, internal_wizard, WIZARD_COMPARE);
|
||||
#undef WIZARD_COMPARE
|
||||
if (found) {
|
||||
if (found
|
||||
&& !((flags & AST_SORCERY_WIZARD_APPLY_ALLOW_DUPLICATE) || found->allow_duplicates)) {
|
||||
ast_debug(1, "Wizard %s already applied to object type %s\n",
|
||||
wizard->callbacks.name, object_type->name);
|
||||
internal_wizard->callbacks.name, object_type->name);
|
||||
AST_VECTOR_RW_UNLOCK(&object_type->wizards);
|
||||
ast_module_unref(wizard->callbacks.module);
|
||||
ast_module_unref(internal_wizard->callbacks.module);
|
||||
return AST_SORCERY_APPLY_DUPLICATE;
|
||||
}
|
||||
}
|
||||
|
||||
ast_debug(5, "Calling wizard %s open callback on object type %s\n",
|
||||
name, object_type->name);
|
||||
if (wizard->callbacks.open && !(object_wizard->data = wizard->callbacks.open(data))) {
|
||||
wizard_type_name, object_type->name);
|
||||
if (internal_wizard->callbacks.open && !(object_wizard->data = internal_wizard->callbacks.open(wizard_args))) {
|
||||
ast_log(LOG_WARNING, "Wizard '%s' failed to open mapping for object type '%s' with data: %s\n",
|
||||
name, object_type->name, S_OR(data, ""));
|
||||
wizard_type_name, object_type->name, S_OR(wizard_args, ""));
|
||||
AST_VECTOR_RW_UNLOCK(&object_type->wizards);
|
||||
ast_module_unref(wizard->callbacks.module);
|
||||
ast_module_unref(internal_wizard->callbacks.module);
|
||||
return AST_SORCERY_APPLY_FAIL;
|
||||
}
|
||||
|
||||
object_wizard->wizard = ao2_bump(wizard);
|
||||
object_wizard->caching = caching;
|
||||
object_wizard->wizard = ao2_bump(internal_wizard);
|
||||
object_wizard->caching = !!(flags & AST_SORCERY_WIZARD_APPLY_CACHING);
|
||||
object_wizard->read_only = !!(flags & AST_SORCERY_WIZARD_APPLY_READONLY);
|
||||
if (wizard_args) {
|
||||
strcpy(object_wizard->wizard_args, wizard_args); /* Safe */
|
||||
}
|
||||
|
||||
if (position == AST_SORCERY_WIZARD_POSITION_LAST) {
|
||||
position = AST_VECTOR_SIZE(&object_type->wizards);
|
||||
@@ -895,17 +944,36 @@ enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sor
|
||||
}
|
||||
|
||||
NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, wizard_mapped,
|
||||
sorcery->module_name, sorcery, type, &wizard->callbacks, data, object_wizard->data);
|
||||
sorcery->module_name, sorcery, object_type_name, &internal_wizard->callbacks, wizard_args,
|
||||
object_wizard->data);
|
||||
|
||||
if (wizard) {
|
||||
*wizard = &internal_wizard->callbacks;
|
||||
}
|
||||
if (wizard_data) {
|
||||
*wizard_data = object_wizard->data;
|
||||
}
|
||||
|
||||
return AST_SORCERY_APPLY_SUCCESS;
|
||||
}
|
||||
|
||||
/*! \brief Internal function which creates an object type and inserts a wizard mapping */
|
||||
enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sorcery *sorcery,
|
||||
const char *object_type_name, const char *module, const char *wizard_type_name,
|
||||
const char *wizard_args, unsigned int caching, int position)
|
||||
{
|
||||
return __ast_sorcery_object_type_insert_wizard(sorcery, object_type_name, module, wizard_type_name,
|
||||
wizard_args, caching ? AST_SORCERY_WIZARD_APPLY_CACHING : AST_SORCERY_WIZARD_APPLY_NONE,
|
||||
position, NULL, NULL);
|
||||
}
|
||||
|
||||
/*! \brief Internal function which creates an object type and adds a wizard mapping */
|
||||
enum ast_sorcery_apply_result __ast_sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery,
|
||||
const char *type, const char *module, const char *name, const char *data, unsigned int caching)
|
||||
const char *object_type_name, const char *module, const char *wizard_type_name,
|
||||
const char *wizard_args, unsigned int caching)
|
||||
{
|
||||
return __ast_sorcery_insert_wizard_mapping(sorcery, type, module, name, data,
|
||||
caching, AST_SORCERY_WIZARD_POSITION_LAST);
|
||||
return __ast_sorcery_insert_wizard_mapping(sorcery, object_type_name, module, wizard_type_name,
|
||||
wizard_args, caching, AST_SORCERY_WIZARD_POSITION_LAST);
|
||||
}
|
||||
|
||||
enum ast_sorcery_apply_result __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, const char *module)
|
||||
@@ -1904,7 +1972,7 @@ struct ao2_container *ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *s
|
||||
/*! \brief Internal function which returns if the wizard has created the object */
|
||||
static int sorcery_wizard_create(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details)
|
||||
{
|
||||
if (!object_wizard->wizard->callbacks.create) {
|
||||
if (!object_wizard->wizard->callbacks.create || object_wizard->read_only) {
|
||||
ast_debug(5, "Sorcery wizard '%s' does not support creation\n", object_wizard->wizard->callbacks.name);
|
||||
return 0;
|
||||
}
|
||||
@@ -2015,7 +2083,7 @@ static int sorcery_observers_notify_update(void *data)
|
||||
/*! \brief Internal function which returns if a wizard has updated the object */
|
||||
static int sorcery_wizard_update(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details)
|
||||
{
|
||||
if (!object_wizard->wizard->callbacks.update) {
|
||||
if (!object_wizard->wizard->callbacks.update || object_wizard->read_only) {
|
||||
ast_debug(5, "Sorcery wizard '%s' does not support updating\n", object_wizard->wizard->callbacks.name);
|
||||
return 0;
|
||||
}
|
||||
@@ -2103,7 +2171,7 @@ static int sorcery_observers_notify_delete(void *data)
|
||||
/*! \brief Internal function which returns if a wizard has deleted the object */
|
||||
static int sorcery_wizard_delete(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details)
|
||||
{
|
||||
if (!object_wizard->wizard->callbacks.delete) {
|
||||
if (!object_wizard->wizard->callbacks.delete || object_wizard->read_only) {
|
||||
ast_debug(5, "Sorcery wizard '%s' does not support deletion\n", object_wizard->wizard->callbacks.name);
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user