mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-06 12:36:58 +00:00
Add support for retrieving multiple objects from sorcery using a regex on their id.
Review: https://reviewboard.asterisk.org/r/2329/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@381614 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -197,6 +197,9 @@ struct ast_sorcery_wizard {
|
|||||||
/*! \brief Callback for retrieving an object using an id */
|
/*! \brief Callback for retrieving an object using an id */
|
||||||
void *(*retrieve_id)(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id);
|
void *(*retrieve_id)(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id);
|
||||||
|
|
||||||
|
/*! \brief Callback for retrieving multiple objects using a regex on their id */
|
||||||
|
void (*retrieve_regex)(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
|
||||||
|
|
||||||
/*! \brief Optional callback for retrieving an object using fields */
|
/*! \brief Optional callback for retrieving an object using fields */
|
||||||
void *(*retrieve_fields)(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields);
|
void *(*retrieve_fields)(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields);
|
||||||
|
|
||||||
@@ -548,6 +551,20 @@ void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *
|
|||||||
*/
|
*/
|
||||||
void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields);
|
void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Retrieve multiple objects using a regular expression on their id
|
||||||
|
*
|
||||||
|
* \param sorcery Pointer to a sorcery structure
|
||||||
|
* \param type Type of object to retrieve
|
||||||
|
* \param regex Regular expression
|
||||||
|
*
|
||||||
|
* \retval non-NULL if error occurs
|
||||||
|
* \retval NULL success
|
||||||
|
*
|
||||||
|
* \note The provided regex is treated as extended case sensitive.
|
||||||
|
*/
|
||||||
|
struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Update an object
|
* \brief Update an object
|
||||||
*
|
*
|
||||||
|
@@ -959,6 +959,30 @@ void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const ch
|
|||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
|
||||||
|
struct ao2_container *objects;
|
||||||
|
struct ao2_iterator i;
|
||||||
|
struct ast_sorcery_object_wizard *wizard;
|
||||||
|
|
||||||
|
if (!object_type || !(objects = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = ao2_iterator_init(object_type->wizards, 0);
|
||||||
|
for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
|
||||||
|
if (!wizard->wizard->retrieve_regex) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
wizard->wizard->retrieve_regex(sorcery, wizard->data, object_type->name, objects, regex);
|
||||||
|
}
|
||||||
|
ao2_iterator_destroy(&i);
|
||||||
|
|
||||||
|
return objects;
|
||||||
|
}
|
||||||
|
|
||||||
/*! \brief Internal function which returns if the wizard has created the object */
|
/*! \brief Internal function which returns if the wizard has created the object */
|
||||||
static int sorcery_wizard_create(void *obj, void *arg, int flags)
|
static int sorcery_wizard_create(void *obj, void *arg, int flags)
|
||||||
{
|
{
|
||||||
|
@@ -32,6 +32,8 @@
|
|||||||
|
|
||||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
|
|
||||||
|
#include <regex.h>
|
||||||
|
|
||||||
#include "asterisk/module.h"
|
#include "asterisk/module.h"
|
||||||
#include "asterisk/sorcery.h"
|
#include "asterisk/sorcery.h"
|
||||||
#include "asterisk/astobj2.h"
|
#include "asterisk/astobj2.h"
|
||||||
@@ -70,6 +72,9 @@ struct sorcery_config_fields_cmp_params {
|
|||||||
/*! \brief Pointer to the fields to check */
|
/*! \brief Pointer to the fields to check */
|
||||||
const struct ast_variable *fields;
|
const struct ast_variable *fields;
|
||||||
|
|
||||||
|
/*! \brief Regular expression for checking object id */
|
||||||
|
regex_t *regex;
|
||||||
|
|
||||||
/*! \brief Optional container to put object into */
|
/*! \brief Optional container to put object into */
|
||||||
struct ao2_container *container;
|
struct ao2_container *container;
|
||||||
};
|
};
|
||||||
@@ -81,6 +86,7 @@ static void *sorcery_config_retrieve_id(const struct ast_sorcery *sorcery, void
|
|||||||
static void *sorcery_config_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields);
|
static void *sorcery_config_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields);
|
||||||
static void sorcery_config_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
|
static void sorcery_config_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
|
||||||
const struct ast_variable *fields);
|
const struct ast_variable *fields);
|
||||||
|
static void sorcery_config_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
|
||||||
static void sorcery_config_close(void *data);
|
static void sorcery_config_close(void *data);
|
||||||
|
|
||||||
static struct ast_sorcery_wizard config_object_wizard = {
|
static struct ast_sorcery_wizard config_object_wizard = {
|
||||||
@@ -91,6 +97,7 @@ static struct ast_sorcery_wizard config_object_wizard = {
|
|||||||
.retrieve_id = sorcery_config_retrieve_id,
|
.retrieve_id = sorcery_config_retrieve_id,
|
||||||
.retrieve_fields = sorcery_config_retrieve_fields,
|
.retrieve_fields = sorcery_config_retrieve_fields,
|
||||||
.retrieve_multiple = sorcery_config_retrieve_multiple,
|
.retrieve_multiple = sorcery_config_retrieve_multiple,
|
||||||
|
.retrieve_regex = sorcery_config_retrieve_regex,
|
||||||
.close = sorcery_config_close,
|
.close = sorcery_config_close,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -126,13 +133,19 @@ static int sorcery_config_fields_cmp(void *obj, void *arg, int flags)
|
|||||||
RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
|
RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
|
||||||
RAII_VAR(struct ast_variable *, diff, NULL, ast_variables_destroy);
|
RAII_VAR(struct ast_variable *, diff, NULL, ast_variables_destroy);
|
||||||
|
|
||||||
/* If we can't turn the object into an object set OR if differences exist between the fields
|
if (params->regex) {
|
||||||
* passed in and what are present on the object they are not a match.
|
/* If a regular expression has been provided see if it matches, otherwise move on */
|
||||||
*/
|
if (!regexec(params->regex, ast_sorcery_object_get_id(obj), 0, NULL, 0)) {
|
||||||
if (params->fields &&
|
ao2_link(params->container, obj);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else if (params->fields &&
|
||||||
(!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) ||
|
(!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) ||
|
||||||
(ast_sorcery_changeset_create(objset, params->fields, &diff)) ||
|
(ast_sorcery_changeset_create(objset, params->fields, &diff)) ||
|
||||||
diff)) {
|
diff)) {
|
||||||
|
/* If we can't turn the object into an object set OR if differences exist between the fields
|
||||||
|
* passed in and what are present on the object they are not a match.
|
||||||
|
*/
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,6 +203,25 @@ static void sorcery_config_retrieve_multiple(const struct ast_sorcery *sorcery,
|
|||||||
ao2_callback(config_objects, 0, sorcery_config_fields_cmp, ¶ms);
|
ao2_callback(config_objects, 0, sorcery_config_fields_cmp, ¶ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sorcery_config_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
|
||||||
|
{
|
||||||
|
struct sorcery_config *config = data;
|
||||||
|
RAII_VAR(struct ao2_container *, config_objects, ao2_global_obj_ref(config->objects), ao2_cleanup);
|
||||||
|
regex_t expression;
|
||||||
|
struct sorcery_config_fields_cmp_params params = {
|
||||||
|
.sorcery = sorcery,
|
||||||
|
.container = objects,
|
||||||
|
.regex = &expression,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!config_objects || regcomp(&expression, regex, REG_EXTENDED | REG_NOSUB)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ao2_callback(config_objects, 0, sorcery_config_fields_cmp, ¶ms);
|
||||||
|
regfree(&expression);
|
||||||
|
}
|
||||||
|
|
||||||
/*! \brief Internal function which determines if criteria has been met for considering an object set applicable */
|
/*! \brief Internal function which determines if criteria has been met for considering an object set applicable */
|
||||||
static int sorcery_is_criteria_met(struct ast_variable *objset, struct ast_variable *criteria)
|
static int sorcery_is_criteria_met(struct ast_variable *objset, struct ast_variable *criteria)
|
||||||
{
|
{
|
||||||
|
@@ -32,6 +32,8 @@
|
|||||||
|
|
||||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
|
|
||||||
|
#include <regex.h>
|
||||||
|
|
||||||
#include "asterisk/module.h"
|
#include "asterisk/module.h"
|
||||||
#include "asterisk/sorcery.h"
|
#include "asterisk/sorcery.h"
|
||||||
#include "asterisk/astobj2.h"
|
#include "asterisk/astobj2.h"
|
||||||
@@ -45,6 +47,7 @@ static void *sorcery_memory_retrieve_id(const struct ast_sorcery *sorcery, void
|
|||||||
static void *sorcery_memory_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields);
|
static void *sorcery_memory_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields);
|
||||||
static void sorcery_memory_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
|
static void sorcery_memory_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
|
||||||
const struct ast_variable *fields);
|
const struct ast_variable *fields);
|
||||||
|
static void sorcery_memory_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
|
||||||
static int sorcery_memory_update(void *data, void *object);
|
static int sorcery_memory_update(void *data, void *object);
|
||||||
static int sorcery_memory_delete(void *data, void *object);
|
static int sorcery_memory_delete(void *data, void *object);
|
||||||
static void sorcery_memory_close(void *data);
|
static void sorcery_memory_close(void *data);
|
||||||
@@ -56,6 +59,7 @@ static struct ast_sorcery_wizard memory_object_wizard = {
|
|||||||
.retrieve_id = sorcery_memory_retrieve_id,
|
.retrieve_id = sorcery_memory_retrieve_id,
|
||||||
.retrieve_fields = sorcery_memory_retrieve_fields,
|
.retrieve_fields = sorcery_memory_retrieve_fields,
|
||||||
.retrieve_multiple = sorcery_memory_retrieve_multiple,
|
.retrieve_multiple = sorcery_memory_retrieve_multiple,
|
||||||
|
.retrieve_regex = sorcery_memory_retrieve_regex,
|
||||||
.update = sorcery_memory_update,
|
.update = sorcery_memory_update,
|
||||||
.delete = sorcery_memory_delete,
|
.delete = sorcery_memory_delete,
|
||||||
.close = sorcery_memory_close,
|
.close = sorcery_memory_close,
|
||||||
@@ -69,6 +73,9 @@ struct sorcery_memory_fields_cmp_params {
|
|||||||
/*! \brief Pointer to the fields to check */
|
/*! \brief Pointer to the fields to check */
|
||||||
const struct ast_variable *fields;
|
const struct ast_variable *fields;
|
||||||
|
|
||||||
|
/*! \brief Regular expression for checking object id */
|
||||||
|
regex_t *regex;
|
||||||
|
|
||||||
/*! \brief Optional container to put object into */
|
/*! \brief Optional container to put object into */
|
||||||
struct ao2_container *container;
|
struct ao2_container *container;
|
||||||
};
|
};
|
||||||
@@ -101,13 +108,19 @@ static int sorcery_memory_fields_cmp(void *obj, void *arg, int flags)
|
|||||||
RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
|
RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
|
||||||
RAII_VAR(struct ast_variable *, diff, NULL, ast_variables_destroy);
|
RAII_VAR(struct ast_variable *, diff, NULL, ast_variables_destroy);
|
||||||
|
|
||||||
/* If we can't turn the object into an object set OR if differences exist between the fields
|
if (params->regex) {
|
||||||
* passed in and what are present on the object they are not a match.
|
/* If a regular expression has been provided see if it matches, otherwise move on */
|
||||||
*/
|
if (!regexec(params->regex, ast_sorcery_object_get_id(obj), 0, NULL, 0)) {
|
||||||
if (params->fields &&
|
ao2_link(params->container, obj);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else if (params->fields &&
|
||||||
(!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) ||
|
(!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) ||
|
||||||
(ast_sorcery_changeset_create(objset, params->fields, &diff)) ||
|
(ast_sorcery_changeset_create(objset, params->fields, &diff)) ||
|
||||||
diff)) {
|
diff)) {
|
||||||
|
/* If we can't turn the object into an object set OR if differences exist between the fields
|
||||||
|
* passed in and what are present on the object they are not a match.
|
||||||
|
*/
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,6 +167,23 @@ static void sorcery_memory_retrieve_multiple(const struct ast_sorcery *sorcery,
|
|||||||
ao2_callback(data, 0, sorcery_memory_fields_cmp, ¶ms);
|
ao2_callback(data, 0, sorcery_memory_fields_cmp, ¶ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sorcery_memory_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
|
||||||
|
{
|
||||||
|
regex_t expression;
|
||||||
|
struct sorcery_memory_fields_cmp_params params = {
|
||||||
|
.sorcery = sorcery,
|
||||||
|
.container = objects,
|
||||||
|
.regex = &expression,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (regcomp(&expression, regex, REG_EXTENDED | REG_NOSUB)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ao2_callback(data, 0, sorcery_memory_fields_cmp, ¶ms);
|
||||||
|
regfree(&expression);
|
||||||
|
}
|
||||||
|
|
||||||
static int sorcery_memory_update(void *data, void *object)
|
static int sorcery_memory_update(void *data, void *object)
|
||||||
{
|
{
|
||||||
RAII_VAR(void *, existing, NULL, ao2_cleanup);
|
RAII_VAR(void *, existing, NULL, ao2_cleanup);
|
||||||
|
@@ -1419,6 +1419,74 @@ AST_TEST_DEFINE(object_retrieve_multiple_field)
|
|||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AST_TEST_DEFINE(object_retrieve_regex)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
|
||||||
|
RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
|
||||||
|
RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case TEST_INIT:
|
||||||
|
info->name = "object_retrieve_regex";
|
||||||
|
info->category = "/main/sorcery/";
|
||||||
|
info->summary = "sorcery multiple object retrieval using regex unit test";
|
||||||
|
info->description =
|
||||||
|
"Test multiple object retrieval in sorcery using regular expression for matching";
|
||||||
|
return AST_TEST_NOT_RUN;
|
||||||
|
case TEST_EXECUTE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(sorcery = alloc_and_initialize_sorcery())) {
|
||||||
|
ast_test_status_update(test, "Failed to open sorcery structure\n");
|
||||||
|
return AST_TEST_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-98joe"))) {
|
||||||
|
ast_test_status_update(test, "Failed to allocate a known object type\n");
|
||||||
|
return AST_TEST_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ast_sorcery_create(sorcery, obj)) {
|
||||||
|
ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
|
||||||
|
return AST_TEST_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ao2_cleanup(obj);
|
||||||
|
|
||||||
|
if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-93joe"))) {
|
||||||
|
ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
|
||||||
|
return AST_TEST_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ast_sorcery_create(sorcery, obj)) {
|
||||||
|
ast_test_status_update(test, "Failed to create second object using in-memory wizard\n");
|
||||||
|
return AST_TEST_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ao2_cleanup(obj);
|
||||||
|
|
||||||
|
if (!(obj = ast_sorcery_alloc(sorcery, "test", "neener-93joe"))) {
|
||||||
|
ast_test_status_update(test, "Failed to allocate third instance of a known object type\n");
|
||||||
|
return AST_TEST_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ast_sorcery_create(sorcery, obj)) {
|
||||||
|
ast_test_status_update(test, "Failed to create third object using in-memory wizard\n");
|
||||||
|
return AST_TEST_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(objects = ast_sorcery_retrieve_by_regex(sorcery, "test", "^blah-"))) {
|
||||||
|
ast_test_status_update(test, "Failed to retrieve a container of objects\n");
|
||||||
|
return AST_TEST_FAIL;
|
||||||
|
} else if (ao2_container_count(objects) != 2) {
|
||||||
|
ast_test_status_update(test, "Received a container with incorrect number of objects in it\n");
|
||||||
|
return AST_TEST_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AST_TEST_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
AST_TEST_DEFINE(object_update)
|
AST_TEST_DEFINE(object_update)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
|
RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
|
||||||
@@ -2099,6 +2167,7 @@ static int unload_module(void)
|
|||||||
AST_TEST_UNREGISTER(object_retrieve_field);
|
AST_TEST_UNREGISTER(object_retrieve_field);
|
||||||
AST_TEST_UNREGISTER(object_retrieve_multiple_all);
|
AST_TEST_UNREGISTER(object_retrieve_multiple_all);
|
||||||
AST_TEST_UNREGISTER(object_retrieve_multiple_field);
|
AST_TEST_UNREGISTER(object_retrieve_multiple_field);
|
||||||
|
AST_TEST_UNREGISTER(object_retrieve_regex);
|
||||||
AST_TEST_UNREGISTER(object_update);
|
AST_TEST_UNREGISTER(object_update);
|
||||||
AST_TEST_UNREGISTER(object_update_uncreated);
|
AST_TEST_UNREGISTER(object_update_uncreated);
|
||||||
AST_TEST_UNREGISTER(object_delete);
|
AST_TEST_UNREGISTER(object_delete);
|
||||||
@@ -2140,6 +2209,7 @@ static int load_module(void)
|
|||||||
AST_TEST_REGISTER(object_retrieve_field);
|
AST_TEST_REGISTER(object_retrieve_field);
|
||||||
AST_TEST_REGISTER(object_retrieve_multiple_all);
|
AST_TEST_REGISTER(object_retrieve_multiple_all);
|
||||||
AST_TEST_REGISTER(object_retrieve_multiple_field);
|
AST_TEST_REGISTER(object_retrieve_multiple_field);
|
||||||
|
AST_TEST_REGISTER(object_retrieve_regex);
|
||||||
AST_TEST_REGISTER(object_update);
|
AST_TEST_REGISTER(object_update);
|
||||||
AST_TEST_REGISTER(object_update_uncreated);
|
AST_TEST_REGISTER(object_update_uncreated);
|
||||||
AST_TEST_REGISTER(object_delete);
|
AST_TEST_REGISTER(object_delete);
|
||||||
|
Reference in New Issue
Block a user