[svn-commits] file: trunk r381614 - in /trunk: include/asterisk/ main/ res/ tests/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Sat Feb 16 10:24:24 CST 2013


Author: file
Date: Sat Feb 16 10:24:21 2013
New Revision: 381614

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=381614
Log:
Add support for retrieving multiple objects from sorcery using a regex on their id.

Review: https://reviewboard.asterisk.org/r/2329/

Modified:
    trunk/include/asterisk/sorcery.h
    trunk/main/sorcery.c
    trunk/res/res_sorcery_config.c
    trunk/res/res_sorcery_memory.c
    trunk/tests/test_sorcery.c

Modified: trunk/include/asterisk/sorcery.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/sorcery.h?view=diff&rev=381614&r1=381613&r2=381614
==============================================================================
--- trunk/include/asterisk/sorcery.h (original)
+++ trunk/include/asterisk/sorcery.h Sat Feb 16 10:24:21 2013
@@ -197,6 +197,9 @@
 	/*! \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);
 
+	/*! \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 */
 	void *(*retrieve_fields)(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields);
 
@@ -549,6 +552,20 @@
 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
  *
  * \param sorcery Pointer to a sorcery structure

Modified: trunk/main/sorcery.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/sorcery.c?view=diff&rev=381614&r1=381613&r2=381614
==============================================================================
--- trunk/main/sorcery.c (original)
+++ trunk/main/sorcery.c Sat Feb 16 10:24:21 2013
@@ -959,6 +959,30 @@
 	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 */
 static int sorcery_wizard_create(void *obj, void *arg, int flags)
 {

Modified: trunk/res/res_sorcery_config.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_sorcery_config.c?view=diff&rev=381614&r1=381613&r2=381614
==============================================================================
--- trunk/res/res_sorcery_config.c (original)
+++ trunk/res/res_sorcery_config.c Sat Feb 16 10:24:21 2013
@@ -32,6 +32,8 @@
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
+#include <regex.h>
+
 #include "asterisk/module.h"
 #include "asterisk/sorcery.h"
 #include "asterisk/astobj2.h"
@@ -69,6 +71,9 @@
 
 	/*! \brief Pointer to the fields to check */
 	const struct ast_variable *fields;
+
+	/*! \brief Regular expression for checking object id */
+	regex_t *regex;
 
 	/*! \brief Optional container to put object into */
 	struct ao2_container *container;
@@ -81,6 +86,7 @@
 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,
 					     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 struct ast_sorcery_wizard config_object_wizard = {
@@ -91,6 +97,7 @@
 	.retrieve_id = sorcery_config_retrieve_id,
 	.retrieve_fields = sorcery_config_retrieve_fields,
 	.retrieve_multiple = sorcery_config_retrieve_multiple,
+	.retrieve_regex = sorcery_config_retrieve_regex,
 	.close = sorcery_config_close,
 };
 
@@ -126,13 +133,19 @@
 	RAII_VAR(struct ast_variable *, objset, 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
-	 * passed in and what are present on the object they are not a match.
-	 */
-	if (params->fields &&
+	if (params->regex) {
+		/* 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)) {
+			ao2_link(params->container, obj);
+		}
+		return 0;
+	} else if (params->fields &&
 	    (!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) ||
 	     (ast_sorcery_changeset_create(objset, params->fields, &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;
 	}
 
@@ -188,6 +201,25 @@
 	}
 
 	ao2_callback(config_objects, 0, sorcery_config_fields_cmp, &params);
+}
+
+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, &params);
+	regfree(&expression);
 }
 
 /*! \brief Internal function which determines if criteria has been met for considering an object set applicable */

Modified: trunk/res/res_sorcery_memory.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_sorcery_memory.c?view=diff&rev=381614&r1=381613&r2=381614
==============================================================================
--- trunk/res/res_sorcery_memory.c (original)
+++ trunk/res/res_sorcery_memory.c Sat Feb 16 10:24:21 2013
@@ -31,6 +31,8 @@
 #include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <regex.h>
 
 #include "asterisk/module.h"
 #include "asterisk/sorcery.h"
@@ -45,6 +47,7 @@
 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,
 					     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_delete(void *data, void *object);
 static void sorcery_memory_close(void *data);
@@ -56,6 +59,7 @@
 	.retrieve_id = sorcery_memory_retrieve_id,
 	.retrieve_fields = sorcery_memory_retrieve_fields,
 	.retrieve_multiple = sorcery_memory_retrieve_multiple,
+	.retrieve_regex = sorcery_memory_retrieve_regex,
 	.update = sorcery_memory_update,
 	.delete = sorcery_memory_delete,
 	.close = sorcery_memory_close,
@@ -69,6 +73,9 @@
 	/*! \brief Pointer to the fields to check */
 	const struct ast_variable *fields;
 
+	/*! \brief Regular expression for checking object id */
+	regex_t *regex;
+
 	/*! \brief Optional container to put object into */
 	struct ao2_container *container;
 };
@@ -101,13 +108,19 @@
 	RAII_VAR(struct ast_variable *, objset, 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
-	 * passed in and what are present on the object they are not a match.
-	 */
-	if (params->fields &&
+	if (params->regex) {
+		/* 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)) {
+			ao2_link(params->container, obj);
+		}
+		return 0;
+	} else if (params->fields &&
 	    (!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) ||
 	     (ast_sorcery_changeset_create(objset, params->fields, &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;
 	}
 
@@ -154,6 +167,23 @@
 	ao2_callback(data, 0, sorcery_memory_fields_cmp, &params);
 }
 
+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, &params);
+	regfree(&expression);
+}
+
 static int sorcery_memory_update(void *data, void *object)
 {
 	RAII_VAR(void *, existing, NULL, ao2_cleanup);

Modified: trunk/tests/test_sorcery.c
URL: http://svnview.digium.com/svn/asterisk/trunk/tests/test_sorcery.c?view=diff&rev=381614&r1=381613&r2=381614
==============================================================================
--- trunk/tests/test_sorcery.c (original)
+++ trunk/tests/test_sorcery.c Sat Feb 16 10:24:21 2013
@@ -1413,6 +1413,74 @@
 		return AST_TEST_FAIL;
 	} else if (ao2_container_count(objects)) {
 		ast_test_status_update(test, "Received a container with objects when there should be none in it\n");
+		return AST_TEST_FAIL;
+	}
+
+	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;
 	}
 
@@ -2099,6 +2167,7 @@
 	AST_TEST_UNREGISTER(object_retrieve_field);
 	AST_TEST_UNREGISTER(object_retrieve_multiple_all);
 	AST_TEST_UNREGISTER(object_retrieve_multiple_field);
+	AST_TEST_UNREGISTER(object_retrieve_regex);
 	AST_TEST_UNREGISTER(object_update);
 	AST_TEST_UNREGISTER(object_update_uncreated);
 	AST_TEST_UNREGISTER(object_delete);
@@ -2140,6 +2209,7 @@
 	AST_TEST_REGISTER(object_retrieve_field);
 	AST_TEST_REGISTER(object_retrieve_multiple_all);
 	AST_TEST_REGISTER(object_retrieve_multiple_field);
+	AST_TEST_REGISTER(object_retrieve_regex);
 	AST_TEST_REGISTER(object_update);
 	AST_TEST_REGISTER(object_update_uncreated);
 	AST_TEST_REGISTER(object_delete);




More information about the svn-commits mailing list