[asterisk-commits] gtjoseph: branch 12 r428999 - in /branches/12: include/asterisk/ main/ tests/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Dec 5 11:05:21 CST 2014
Author: gtjoseph
Date: Fri Dec 5 11:05:09 2014
New Revision: 428999
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=428999
Log:
sorcery: Add additional observer capabilities.
Add new global, instance and wizard observers.
instance_created
wizard_registered
wizard_unregistered
instance_destroying
instance_loading
instance_loaded
wizard_mapped
object_type_registered
object_type_loading
object_type_loaded
wizard_loading
wizard_loaded
Tested-by: George Joseph
Review: https://reviewboard.asterisk.org/r/4215/
Modified:
branches/12/include/asterisk/sorcery.h
branches/12/include/asterisk/test.h
branches/12/main/sorcery.c
branches/12/tests/test_sorcery.c
Modified: branches/12/include/asterisk/sorcery.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/include/asterisk/sorcery.h?view=diff&rev=428999&r1=428998&r2=428999
==============================================================================
--- branches/12/include/asterisk/sorcery.h (original)
+++ branches/12/include/asterisk/sorcery.h Fri Dec 5 11:05:09 2014
@@ -141,8 +141,9 @@
};
-/*! \brief Forward declaration for the sorcery main structure */
+/*! \brief Forward declaration for the sorcery main structure and wizard structure */
struct ast_sorcery;
+struct ast_sorcery_wizard;
/*!
* \brief A callback function for translating a value into a string
@@ -214,6 +215,62 @@
* \param -1 failure
*/
typedef int (*sorcery_diff_handler)(const void *original, const void *modified, struct ast_variable **changes);
+
+/*! \brief Interface for the global sorcery observer */
+struct ast_sorcery_global_observer {
+ /*! \brief Callback after an instance is created */
+ void (*instance_created)(const char *name, struct ast_sorcery *sorcery);
+
+ /*! \brief Callback after an wizard is registered */
+ void (*wizard_registered)(const char *name,
+ const struct ast_sorcery_wizard *wizard);
+
+ /*! \brief Callback before an instance is destroyed */
+ void (*instance_destroying)(const char *name, struct ast_sorcery *sorcery);
+
+ /*! \brief Callback before a wizard is unregistered */
+ void (*wizard_unregistering)(const char *name,
+ const struct ast_sorcery_wizard *wizard);
+};
+
+/*! \brief Interface for the sorcery instance observer */
+struct ast_sorcery_instance_observer {
+ /*! \brief Callback before instance is loaded/reloaded */
+ void (*instance_loading)(const char *name, const struct ast_sorcery *sorcery,
+ int reloaded);
+
+ /*! \brief Callback after instance is loaded/reloaded */
+ void (*instance_loaded)(const char *name, const struct ast_sorcery *sorcery,
+ int reloaded);
+
+ /*! \brief Callback after a wizard is mapped to an object_type */
+ void (*wizard_mapped)(const char *name, struct ast_sorcery *sorcery,
+ const char *object_type, struct ast_sorcery_wizard *wizard,
+ const char *wizard_args, void *wizard_data);
+
+ /*! \brief Callback after any object_type is registered */
+ void (*object_type_registered)(const char *name, struct ast_sorcery *sorcery,
+ const char *object_type);
+
+ /*! \brief Callback before any object_type is loaded/reloaded */
+ void (*object_type_loading)(const char *name, const struct ast_sorcery *sorcery,
+ const char *object_type, int reloaded);
+
+ /*! \brief Callback after any object_type is loaded/reloaded */
+ void (*object_type_loaded)(const char *name, const struct ast_sorcery *sorcery,
+ const char *object_type, int reloaded);
+};
+
+/*! \brief Interface for the sorcery wizard observer */
+struct ast_sorcery_wizard_observer {
+ /*! \brief Callback before a wizard is loaded/reloaded for any type */
+ void (*wizard_loading)(const char *name, const struct ast_sorcery_wizard *wizard,
+ const char *object_type, int reloaded);
+
+ /*! \brief Callback after a wizard is loaded/reloaded for any type */
+ void (*wizard_loaded)(const char *name, const struct ast_sorcery_wizard *wizard,
+ const char *object_type, int reloaded);
+};
/*! \brief Interface for a sorcery wizard */
struct ast_sorcery_wizard {
@@ -406,6 +463,40 @@
#define ast_sorcery_apply_default(sorcery, type, name, data) \
__ast_sorcery_apply_default((sorcery), (type), AST_MODULE, (name), (data))
+
+/*!
+ * \brief Apply additional object wizard mappings
+ *
+ * \param sorcery Pointer to a sorcery structure
+ * \param type Type of object to apply to
+ * \param module The name of the module, typically AST_MODULE
+ * \param name Name of the wizard to use
+ * \param data Data to be passed to wizard
+ * \param caching Wizard should cache
+ *
+ * \return What occurred when applying the mapping
+ *
+ * \note This should be called *after* applying default mappings
+ */
+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);
+
+/*!
+ * \brief Apply additional object wizard mappings
+ *
+ * \param sorcery Pointer to a sorcery structure
+ * \param type Type of object to apply to
+ * \param module The name of the module, typically AST_MODULE
+ * \param name Name of the wizard to use
+ * \param data Data to be passed to wizard
+ *
+ * \return What occurred when applying the mapping
+ *
+ * \note This should be called *after* applying default mappings
+ */
+#define ast_sorcery_apply_wizard_mapping(sorcery, type, name, data, caching) \
+ __ast_sorcery_apply_wizard_mapping((sorcery), (type), AST_MODULE, (name), (data), (caching));
+
/*!
* \brief Register an object type
*
@@ -794,6 +885,89 @@
int ast_sorcery_diff(const struct ast_sorcery *sorcery, const void *original, const void *modified, struct ast_variable **changes);
/*!
+ * \brief Add a global observer to sorcery
+ *
+ * \param callbacks Implementation of the global observer interface
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ *
+ * \note You must be ready to accept observer invocations before this function is called
+ */
+int ast_sorcery_global_observer_add(const struct ast_sorcery_global_observer *callbacks);
+
+/*!
+ * \brief Remove a global observer from sorcery.
+ *
+ * A global observer is notified...
+ * After a new wizard is registered.
+ * After a new sorcery instance is opened.
+ * Before an instance is destroyed.
+ * Before a wizard is unregistered.
+ *
+ * \param callbacks Implementation of the global observer interface
+ */
+void ast_sorcery_global_observer_remove(const struct ast_sorcery_global_observer *callbacks);
+
+/*!
+ * \brief Add an observer to a sorcery instance
+ *
+ * \param sorcery Pointer to a sorcery structure
+ * \param callbacks Implementation of the instance observer interface
+ *
+ * An instance observer is notified...
+ * Before an instance is loaded or reloaded.
+ * After an instance is loaded or reloaded.
+ * After a wizard is mapped to an object type.
+ * After an object type is registered.
+ * Before an object type is loaded or reloaded.
+ * After an object type is loaded or reloaded.
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ *
+ * \note You must be ready to accept observer invocations before this function is called
+ */
+int ast_sorcery_instance_observer_add(struct ast_sorcery *sorcery,
+ const struct ast_sorcery_instance_observer *callbacks);
+
+/*!
+ * \brief Remove an observer from a sorcery instance
+ *
+ * \param sorcery Pointer to a sorcery structure
+ * \param callbacks Implementation of the instance observer interface
+ */
+void ast_sorcery_instance_observer_remove(struct ast_sorcery *sorcery,
+ const struct ast_sorcery_instance_observer *callbacks);
+
+/*!
+ * \brief Add an observer to a sorcery wizard
+ *
+ * \param sorcery Pointer to a previously registered wizard structure
+ * \param callbacks Implementation of the wizard observer interface
+ *
+ * A wizard observer is notified...
+ * Before a wizard is loaded or reloaded.
+ * After a wizard is loaded or reloaded.
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ *
+ * \note You must be ready to accept observer invocations before this function is called
+ */
+int ast_sorcery_wizard_observer_add(struct ast_sorcery_wizard *wizard,
+ const struct ast_sorcery_wizard_observer *callbacks);
+
+/*!
+ * \brief Remove an observer from a sorcery wizard.
+ *
+ * \param sorcery Pointer to a sorcery structure
+ * \param callbacks Implementation of the wizard observer interface
+ */
+void ast_sorcery_wizard_observer_remove(struct ast_sorcery_wizard *wizard,
+ const struct ast_sorcery_wizard_observer *callbacks);
+
+/*!
* \brief Add an observer to a specific object type
*
* \param sorcery Pointer to a sorcery structure
Modified: branches/12/include/asterisk/test.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/include/asterisk/test.h?view=diff&rev=428999&r1=428998&r2=428999
==============================================================================
--- branches/12/include/asterisk/test.h (original)
+++ branches/12/include/asterisk/test.h Fri Dec 5 11:05:09 2014
@@ -381,10 +381,10 @@
* \param test Currently executing test
* \param condition Boolean condition to check.
*/
-#define ast_test_validate(test, condition) \
+#define ast_test_validate(test, condition, ...) \
do { \
if (!(condition)) { \
- __ast_test_status_update(__FILE__, __PRETTY_FUNCTION__, __LINE__, (test), "Condition failed: %s\n", #condition); \
+ __ast_test_status_update(__FILE__, __PRETTY_FUNCTION__, __LINE__, (test), "%s: %s\n", strlen(#__VA_ARGS__) ? #__VA_ARGS__ : "Condition failed", #condition); \
return AST_TEST_FAIL; \
} \
} while(0)
Modified: branches/12/main/sorcery.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/main/sorcery.c?view=diff&rev=428999&r1=428998&r2=428999
==============================================================================
--- branches/12/main/sorcery.c (original)
+++ branches/12/main/sorcery.c Fri Dec 5 11:05:09 2014
@@ -61,6 +61,29 @@
/*! \brief Number of buckets for object fields (should be prime for performance reasons) */
#define OBJECT_FIELD_BUCKETS 29
+#define NOTIFY_GENERIC_OBSERVERS(container, type, callback, ...) ({ \
+ struct ao2_iterator i = ao2_iterator_init(container, 0); \
+ struct type *observer; \
+ ao2_rdlock(container); \
+ while ((observer = ao2_iterator_next(&i))) { \
+ if (observer->callbacks->callback) { \
+ observer->callbacks->callback(__VA_ARGS__); \
+ } \
+ ao2_cleanup(observer); \
+ } \
+ ao2_unlock(container); \
+ ao2_iterator_cleanup(&i); \
+})
+
+#define NOTIFY_GLOBAL_OBSERVERS(container, callback, ...) \
+ NOTIFY_GENERIC_OBSERVERS(container, sorcery_global_observer, callback, __VA_ARGS__)
+
+#define NOTIFY_INSTANCE_OBSERVERS(container, callback, ...) \
+ NOTIFY_GENERIC_OBSERVERS(container, sorcery_instance_observer, callback, __VA_ARGS__)
+
+#define NOTIFY_WIZARD_OBSERVERS(container, callback, ...) \
+ NOTIFY_GENERIC_OBSERVERS(container, sorcery_wizard_observer, callback, __VA_ARGS__)
+
/*! \brief Thread pool for observers */
static struct ast_threadpool *threadpool;
@@ -154,10 +177,19 @@
intptr_t args[];
};
+/*! \brief Structure for an internal wizard instance */
+struct ast_sorcery_internal_wizard {
+ /*! \brief Wizard interface itself */
+ struct ast_sorcery_wizard callbacks;
+
+ /*! \brief Observers */
+ struct ao2_container *observers;
+};
+
/*! \brief Structure for a wizard instance which operates on objects */
struct ast_sorcery_object_wizard {
/*! \brief Wizard interface itself */
- struct ast_sorcery_wizard *wizard;
+ struct ast_sorcery_internal_wizard *wizard;
/*! \brief Unique data for the wizard */
void *data;
@@ -170,6 +202,10 @@
struct ast_sorcery {
/*! \brief Container for known object types */
struct ao2_container *types;
+
+ /*! \brief Observers */
+ struct ao2_container *observers;
+
/*! \brief The name of the module owning this sorcery instance */
char module_name[0];
};
@@ -188,6 +224,30 @@
/*! \brief Registered sorcery wizards */
static struct ao2_container *wizards;
+
+/* The following 3 observer wrappers must name their
+ * external observer 'callbacks' and it must be
+ * the first member of the structure. Common macros
+ * and container callbacks depend on it.
+ */
+
+/*! \brief A global observer wrapper */
+struct sorcery_global_observer {
+ const struct ast_sorcery_global_observer *callbacks;
+};
+
+/*! \brief An instance observer wrapper */
+struct sorcery_instance_observer {
+ const struct ast_sorcery_instance_observer *callbacks;
+};
+
+/*! \brief A wizard observer wrapper */
+struct sorcery_wizard_observer {
+ const struct ast_sorcery_wizard_observer *callbacks;
+};
+
+/*! \brief Registered global observers */
+struct ao2_container *observers;
/*! \brief Registered sorcery instances */
static struct ao2_container *instances;
@@ -264,7 +324,7 @@
/*! \brief Hashing function for sorcery wizards */
static int sorcery_wizard_hash(const void *obj, const int flags)
{
- const struct ast_sorcery_wizard *object;
+ const struct ast_sorcery_internal_wizard *object;
const char *key;
switch (flags & OBJ_SEARCH_MASK) {
@@ -273,7 +333,7 @@
break;
case OBJ_SEARCH_OBJECT:
object = obj;
- key = object->name;
+ key = object->callbacks.name;
break;
default:
ast_assert(0);
@@ -285,20 +345,20 @@
/*! \brief Comparator function for sorcery wizards */
static int sorcery_wizard_cmp(void *obj, void *arg, int flags)
{
- const struct ast_sorcery_wizard *object_left = obj;
- const struct ast_sorcery_wizard *object_right = arg;
+ const struct ast_sorcery_internal_wizard *object_left = obj;
+ const struct ast_sorcery_internal_wizard *object_right = arg;
const char *right_key = arg;
int cmp;
switch (flags & OBJ_SEARCH_MASK) {
case OBJ_SEARCH_OBJECT:
- right_key = object_right->name;
+ right_key = object_right->callbacks.name;
/* Fall through */
case OBJ_SEARCH_KEY:
- cmp = strcmp(object_left->name, right_key);
+ cmp = strcmp(object_left->callbacks.name, right_key);
break;
case OBJ_SEARCH_PARTIAL_KEY:
- cmp = strncmp(object_left->name, right_key, strlen(right_key));
+ cmp = strncmp(object_left->callbacks.name, right_key, strlen(right_key));
break;
default:
cmp = 0;
@@ -370,6 +430,8 @@
{
ao2_cleanup(wizards);
wizards = NULL;
+ ao2_cleanup(observers);
+ observers = NULL;
ao2_cleanup(instances);
instances = NULL;
}
@@ -444,6 +506,13 @@
return -1;
}
+ observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL);
+ if (!observers) {
+ sorcery_cleanup();
+ sorcery_exit();
+ return -1;
+ }
+
instances = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK, INSTANCE_BUCKETS,
sorcery_instance_hash, sorcery_instance_cmp);
if (!instances) {
@@ -458,9 +527,16 @@
return 0;
}
+static void sorcery_internal_wizard_destructor(void *obj)
+{
+ struct ast_sorcery_internal_wizard *wizard = obj;
+
+ ao2_cleanup(wizard->observers);
+}
+
int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module)
{
- struct ast_sorcery_wizard *wizard;
+ struct ast_sorcery_internal_wizard *wizard;
int res = -1;
ast_assert(!ast_strlen_zero(interface->name));
@@ -473,17 +549,25 @@
goto done;
}
- if (!(wizard = ao2_alloc(sizeof(*wizard), NULL))) {
+ if (!(wizard = ao2_alloc(sizeof(*wizard), sorcery_internal_wizard_destructor))) {
goto done;
}
- *wizard = *interface;
- wizard->module = module;
+ wizard->callbacks = *interface;
+ wizard->callbacks.module = module;
+
+ wizard->observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL);
+ if (!wizard->observers) {
+ goto done;
+ }
ao2_link_flags(wizards, wizard, OBJ_NOLOCK);
res = 0;
ast_verb(2, "Sorcery registered wizard '%s'\n", interface->name);
+
+ NOTIFY_GLOBAL_OBSERVERS(observers, wizard_registered,
+ interface->name, interface);
done:
ao2_cleanup(wizard);
@@ -494,9 +578,13 @@
int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
{
- RAII_VAR(struct ast_sorcery_wizard *, wizard, ao2_find(wizards, interface->name, OBJ_KEY | OBJ_UNLINK), ao2_cleanup);
+ struct ast_sorcery_internal_wizard *wizard =
+ interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL;
if (wizard) {
+ NOTIFY_GLOBAL_OBSERVERS(observers, wizard_unregistering, wizard->callbacks.name, &wizard->callbacks);
+ ao2_unlink(wizards, wizard);
+ ao2_ref(wizard, -1);
ast_verb(2, "Sorcery unregistered wizard '%s'\n", interface->name);
return 0;
} else {
@@ -504,11 +592,105 @@
}
}
+/*! \brief Internal callback function for removing a generic observer */
+static int sorcery_generic_observer_remove(void *obj, void *arg, int flags)
+{
+ const struct sorcery_global_observer *observer = obj;
+
+ return (observer->callbacks == arg) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+int ast_sorcery_global_observer_add(const struct ast_sorcery_global_observer *callbacks)
+{
+ struct sorcery_global_observer *cb;
+
+ cb = ao2_alloc(sizeof(*cb), NULL);
+ if (!cb) {
+ return -1;
+ }
+
+ cb->callbacks = callbacks;
+ ao2_link(observers, cb);
+ ao2_ref(cb, -1);
+
+ return 0;
+}
+
+void ast_sorcery_global_observer_remove(
+ const struct ast_sorcery_global_observer *callbacks)
+{
+ ao2_callback(observers, OBJ_NODATA | OBJ_UNLINK, sorcery_generic_observer_remove, (void *)callbacks);
+}
+
+int ast_sorcery_instance_observer_add(struct ast_sorcery *sorcery,
+ const struct ast_sorcery_instance_observer *callbacks)
+{
+ struct sorcery_instance_observer *cb;
+
+ cb = ao2_alloc(sizeof(*cb), NULL);
+ if (!cb) {
+ return -1;
+ }
+
+ cb->callbacks = callbacks;
+ ao2_link(sorcery->observers, cb);
+ ao2_ref(cb, -1);
+
+ return 0;
+}
+
+void ast_sorcery_instance_observer_remove(struct ast_sorcery *sorcery,
+ const struct ast_sorcery_instance_observer *callbacks)
+{
+ ao2_callback(sorcery->observers, OBJ_NODATA | OBJ_UNLINK, sorcery_generic_observer_remove, (void *)callbacks);
+}
+
+int ast_sorcery_wizard_observer_add(struct ast_sorcery_wizard *interface,
+ const struct ast_sorcery_wizard_observer *callbacks)
+{
+ RAII_VAR(struct ast_sorcery_internal_wizard *, wizard,
+ interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL,
+ ao2_cleanup);
+
+ if (wizard) {
+ struct sorcery_wizard_observer *cb;
+
+ cb = ao2_alloc(sizeof(*cb), NULL);
+ if (!cb) {
+ return -1;
+ }
+
+ cb->callbacks = callbacks;
+ ao2_link(wizard->observers, cb);
+ ao2_ref(cb, -1);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+void ast_sorcery_wizard_observer_remove(struct ast_sorcery_wizard *interface,
+ const struct ast_sorcery_wizard_observer *callbacks)
+{
+ RAII_VAR(struct ast_sorcery_internal_wizard *, wizard,
+ interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL,
+ ao2_cleanup);
+
+ if (wizard) {
+ ao2_callback(wizard->observers, OBJ_NODATA | OBJ_UNLINK, sorcery_generic_observer_remove, (void *)callbacks);
+ }
+}
+
/*! \brief Destructor called when sorcery structure is destroyed */
static void sorcery_destructor(void *obj)
{
struct ast_sorcery *sorcery = obj;
+ if (sorcery->observers) {
+ NOTIFY_GLOBAL_OBSERVERS(observers, instance_destroying, sorcery->module_name, sorcery);
+ }
+ ao2_cleanup(sorcery->observers);
ao2_cleanup(sorcery->types);
}
@@ -582,6 +764,12 @@
goto done;
}
+ if (!(sorcery->observers = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK, 0, NULL, NULL))) {
+ ao2_ref(sorcery, -1);
+ sorcery = NULL;
+ goto done;
+ }
+
strcpy(sorcery->module_name, module_name); /* Safe */
if (__ast_sorcery_apply_config(sorcery, module_name, module_name) == AST_SORCERY_APPLY_FAIL) {
@@ -593,6 +781,8 @@
ao2_link_flags(instances, sorcery, OBJ_NOLOCK);
+ NOTIFY_GLOBAL_OBSERVERS(observers, instance_created, module_name, sorcery);
+
done:
ao2_unlock(instances);
return sorcery;
@@ -685,22 +875,22 @@
struct ast_sorcery_object_wizard *object_wizard = obj;
if (object_wizard->data) {
- object_wizard->wizard->close(object_wizard->data);
+ object_wizard->wizard->callbacks.close(object_wizard->data);
}
if (object_wizard->wizard) {
- ast_module_unref(object_wizard->wizard->module);
+ ast_module_unref(object_wizard->wizard->callbacks.module);
}
ao2_cleanup(object_wizard->wizard);
}
/*! \brief Internal function which creates an object type and adds a wizard mapping */
-static enum ast_sorcery_apply_result sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery,
+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)
{
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
- RAII_VAR(struct ast_sorcery_wizard *, wizard, ao2_find(wizards, name, 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);
int created = 0;
@@ -721,17 +911,17 @@
found = ao2_find(object_type->wizards, wizard, OBJ_SEARCH_OBJECT);
if (found) {
ast_debug(1, "Wizard %s already applied to object type %s\n",
- wizard->name, object_type->name);
+ wizard->callbacks.name, object_type->name);
ao2_cleanup(found);
return AST_SORCERY_APPLY_DUPLICATE;
}
}
- if (wizard->open && !(object_wizard->data = wizard->open(data))) {
+ if (wizard->callbacks.open && !(object_wizard->data = wizard->callbacks.open(data))) {
return AST_SORCERY_APPLY_FAIL;
}
- ast_module_ref(wizard->module);
+ ast_module_ref(wizard->callbacks.module);
object_wizard->wizard = ao2_bump(wizard);
object_wizard->caching = caching;
@@ -741,6 +931,9 @@
if (created) {
ao2_link(sorcery->types, object_type);
}
+
+ NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, wizard_mapped,
+ sorcery->module_name, sorcery, type, &wizard->callbacks, data, object_wizard->data);
return AST_SORCERY_APPLY_SUCCESS;
}
@@ -780,7 +973,7 @@
}
/* Any error immediately causes us to stop */
- if (sorcery_apply_wizard_mapping(sorcery, type, module, wizard, data, caching) == AST_SORCERY_APPLY_FAIL) {
+ if (__ast_sorcery_apply_wizard_mapping(sorcery, type, module, wizard, data, caching) == AST_SORCERY_APPLY_FAIL) {
res = AST_SORCERY_APPLY_FAIL;
break;
}
@@ -800,7 +993,7 @@
return AST_SORCERY_APPLY_DEFAULT_UNNECESSARY;
}
- return sorcery_apply_wizard_mapping(sorcery, type, module, name, data, 0);
+ return __ast_sorcery_apply_wizard_mapping(sorcery, type, module, name, data, 0);
}
static int sorcery_extended_config_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
@@ -848,6 +1041,9 @@
if (ast_sorcery_object_fields_register(sorcery, type, "^@", sorcery_extended_config_handler, sorcery_extended_fields_handler)) {
return -1;
}
+
+ NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, object_type_registered,
+ sorcery->module_name, sorcery, type);
return 0;
}
@@ -988,10 +1184,16 @@
return 0;
}
- load = !details->reload ? wizard->wizard->load : wizard->wizard->reload;
+ load = !details->reload ? wizard->wizard->callbacks.load : wizard->wizard->callbacks.reload;
if (load) {
+ NOTIFY_WIZARD_OBSERVERS(wizard->wizard->observers, wizard_loading,
+ wizard->wizard->callbacks.name, &wizard->wizard->callbacks, details->type, details->reload);
+
load(wizard->data, details->sorcery, details->type);
+
+ NOTIFY_WIZARD_OBSERVERS(wizard->wizard->observers, wizard_loaded,
+ wizard->wizard->callbacks.name, &wizard->wizard->callbacks, details->type, details->reload);
}
return 0;
@@ -1055,6 +1257,10 @@
struct sorcery_load_details *details = arg;
details->type = type->name;
+
+ NOTIFY_INSTANCE_OBSERVERS(details->sorcery->observers, object_type_loading,
+ details->sorcery->module_name, details->sorcery, type->name, details->reload);
+
ao2_callback(type->wizards, OBJ_NODATA, sorcery_wizard_load, details);
if (ao2_container_count(type->observers)) {
@@ -1064,6 +1270,9 @@
ao2_cleanup(invocation);
}
}
+
+ NOTIFY_INSTANCE_OBSERVERS(details->sorcery->observers, object_type_loaded,
+ details->sorcery->module_name, details->sorcery, type->name, details->reload);
return 0;
}
@@ -1075,7 +1284,13 @@
.reload = 0,
};
+ NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loading,
+ sorcery->module_name, sorcery, 0);
+
ao2_callback(sorcery->types, OBJ_NODATA, sorcery_object_load, &details);
+
+ NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loaded,
+ sorcery->module_name, sorcery, 0);
}
void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type)
@@ -1100,7 +1315,14 @@
.reload = 1,
};
+ NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loading,
+ sorcery->module_name, sorcery, 1);
+
ao2_callback(sorcery->types, OBJ_NODATA, sorcery_object_load, &details);
+
+ NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loaded,
+ sorcery->module_name, sorcery, 1);
+
}
void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
@@ -1304,20 +1526,6 @@
return res;
}
-static const struct ast_variable *sorcery_find_field(const struct ast_variable *fields, const char *name)
-{
- const struct ast_variable *field;
-
- /* Search the linked list of fields to find the correct one */
- for (field = fields; field; field = field->next) {
- if (!strcmp(field->name, name)) {
- return field;
- }
- }
-
- return NULL;
-}
-
int ast_sorcery_changeset_create(const struct ast_variable *original, const struct ast_variable *modified, struct ast_variable **changes)
{
const struct ast_variable *field;
@@ -1331,9 +1539,9 @@
}
for (field = modified; field; field = field->next) {
- const struct ast_variable *old = sorcery_find_field(original, field->name);
-
- if (!old || strcmp(old->value, field->value)) {
+ const char *old_value = ast_variable_find_in_list(original, field->name);
+
+ if (!old_value || strcmp(old_value, field->value)) {
struct ast_variable *tmp;
if (!(tmp = ast_variable_new(field->name, field->value, ""))) {
@@ -1477,11 +1685,11 @@
const struct ast_sorcery_object_wizard *object_wizard = obj;
const struct sorcery_details *details = arg;
- if (!object_wizard->caching || !object_wizard->wizard->create) {
+ if (!object_wizard->caching || !object_wizard->wizard->callbacks.create) {
return 0;
}
- object_wizard->wizard->create(details->sorcery, object_wizard->data, details->obj);
+ object_wizard->wizard->callbacks.create(details->sorcery, object_wizard->data, details->obj);
return 0;
}
@@ -1500,8 +1708,8 @@
i = ao2_iterator_init(object_type->wizards, 0);
for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
- if (wizard->wizard->retrieve_id &&
- !(object = wizard->wizard->retrieve_id(sorcery, wizard->data, object_type->name, id))) {
+ if (wizard->wizard->callbacks.retrieve_id &&
+ !(object = wizard->wizard->callbacks.retrieve_id(sorcery, wizard->data, object_type->name, id))) {
continue;
}
@@ -1542,12 +1750,12 @@
i = ao2_iterator_init(object_type->wizards, 0);
for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
- if (wizard->wizard->retrieve_multiple) {
- wizard->wizard->retrieve_multiple(sorcery, wizard->data, object_type->name, object, fields);
+ if (wizard->wizard->callbacks.retrieve_multiple) {
+ wizard->wizard->callbacks.retrieve_multiple(sorcery, wizard->data, object_type->name, object, fields);
}
- } else if (fields && wizard->wizard->retrieve_fields) {
- if (wizard->wizard->retrieve_fields) {
- object = wizard->wizard->retrieve_fields(sorcery, wizard->data, object_type->name, fields);
+ } else if (fields && wizard->wizard->callbacks.retrieve_fields) {
+ if (wizard->wizard->callbacks.retrieve_fields) {
+ object = wizard->wizard->callbacks.retrieve_fields(sorcery, wizard->data, object_type->name, fields);
}
}
@@ -1583,11 +1791,11 @@
i = ao2_iterator_init(object_type->wizards, 0);
for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
- if (!wizard->wizard->retrieve_regex) {
+ if (!wizard->wizard->callbacks.retrieve_regex) {
continue;
}
- wizard->wizard->retrieve_regex(sorcery, wizard->data, object_type->name, objects, regex);
+ wizard->wizard->callbacks.retrieve_regex(sorcery, wizard->data, object_type->name, objects, regex);
}
ao2_iterator_destroy(&i);
@@ -1600,13 +1808,13 @@
const struct ast_sorcery_object_wizard *object_wizard = obj;
const struct sorcery_details *details = arg;
- if (!object_wizard->wizard->create) {
+ if (!object_wizard->wizard->callbacks.create) {
ast_assert(0);
ast_log(LOG_ERROR, "Sorcery wizard '%s' doesn't contain a 'create' virtual function.\n",
- object_wizard->wizard->name);
+ object_wizard->wizard->callbacks.name);
return 0;
}
- return (!object_wizard->caching && !object_wizard->wizard->create(details->sorcery, object_wizard->data, details->obj)) ? CMP_MATCH | CMP_STOP : 0;
+ return (!object_wizard->caching && !object_wizard->wizard->callbacks.create(details->sorcery, object_wizard->data, details->obj)) ? CMP_MATCH | CMP_STOP : 0;
}
/*! \brief Internal callback function which notifies an individual observer that an object has been created */
@@ -1687,7 +1895,7 @@
const struct ast_sorcery_object_wizard *object_wizard = obj;
const struct sorcery_details *details = arg;
- return (object_wizard->wizard->update && !object_wizard->wizard->update(details->sorcery, object_wizard->data, details->obj) &&
+ return (object_wizard->wizard->callbacks.update && !object_wizard->wizard->callbacks.update(details->sorcery, object_wizard->data, details->obj) &&
!object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0;
}
@@ -1746,7 +1954,7 @@
const struct ast_sorcery_object_wizard *object_wizard = obj;
const struct sorcery_details *details = arg;
- return (object_wizard->wizard->delete && !object_wizard->wizard->delete(details->sorcery, object_wizard->data, details->obj) &&
+ return (object_wizard->wizard->callbacks.delete && !object_wizard->wizard->callbacks.delete(details->sorcery, object_wizard->data, details->obj) &&
!object_wizard->caching) ? CMP_MATCH | CMP_STOP : 0;
}
Modified: branches/12/tests/test_sorcery.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/tests/test_sorcery.c?view=diff&rev=428999&r1=428998&r2=428999
==============================================================================
--- branches/12/tests/test_sorcery.c (original)
+++ branches/12/tests/test_sorcery.c Fri Dec 5 11:05:09 2014
@@ -3033,6 +3033,309 @@
ast_sorcery_object_fields_register(sorcery, "test", "^", test_sorcery_regex_handler, test_sorcery_regex_fields);
ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "goober"));
+
+ return AST_TEST_PASS;
+}
+
+static int event_observed;
+
+static void wizard_observer(const char *name, const struct ast_sorcery_wizard *wizard)
+{
+ if (!strcmp(wizard->name, "test")) {
+ event_observed = 1;
+ }
+}
+
+static void instance_observer(const char *name, struct ast_sorcery *sorcery)
+{
+ if (!strcmp(name, "test_sorcery")) {
+ event_observed = 1;
+ }
+}
+
+AST_TEST_DEFINE(global_observation)
+{
+ RAII_VAR(struct ast_sorcery_wizard *, wizard, &test_wizard, ast_sorcery_wizard_unregister);
+ RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+ const struct ast_sorcery_global_observer observer = {
+ .wizard_registered = wizard_observer,
+ .instance_created = instance_observer,
+ .wizard_unregistering = wizard_observer,
+ .instance_destroying = instance_observer,
+ };
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "global_observation";
+ info->category = "/main/sorcery/";
+ info->summary = "global sorcery observation test";
+ info->description =
+ "Test observation of sorcery (global)";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ ast_sorcery_global_observer_add(&observer);
+
+ event_observed = 0;
+ ast_sorcery_wizard_register(wizard);
+ ast_test_validate(test, (event_observed == 1), "Wizard registered failed");
+
+ event_observed = 0;
+ ast_sorcery_wizard_unregister(wizard);
+ ast_test_validate(test, (event_observed == 1), "Wizard unregistered failed");
+
+ event_observed = 0;
+ sorcery = ast_sorcery_open();
+ ast_test_validate(test, (event_observed == 1), "Instance created failed");
+
+ event_observed = 0;
+ ast_sorcery_unref(sorcery);
+ sorcery = NULL;
+ ast_test_validate(test, (event_observed == 1), "Instance destroyed failed");
+
+ ast_sorcery_global_observer_remove(&observer);
+ event_observed = 0;
+ ast_sorcery_wizard_register(&test_wizard);
+ ast_test_validate(test, (event_observed == 0), "Observer removed failed");
+
+ return AST_TEST_PASS;
+}
+
+static void instance_loaded_observer(const char *name, const struct ast_sorcery *sorcery,
+ int reloaded)
+{
+ if (!strcmp(name, "test_sorcery") && !reloaded) {
+ event_observed++;
+ }
+}
+
+static void instance_reloaded_observer(const char *name,
+ const struct ast_sorcery *sorcery, int reloaded)
+{
+ if (!strcmp(name, "test_sorcery") && reloaded) {
+ event_observed++;
+ }
+}
+
+static void wizard_mapped_observer(const char *name, struct ast_sorcery *sorcery,
+ const char *object_type, struct ast_sorcery_wizard *wizard,
+ const char *wizard_args, void *wizard_data)
+{
+ if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
+ && !strcmp(wizard->name, "memory") && !strcmp(wizard_args, "memwiz")) {
+ event_observed++;
+ }
+}
+
+static void object_type_registered_observer(const char *name,
+ struct ast_sorcery *sorcery, const char *object_type)
+{
+ if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")) {
+ event_observed++;
+ }
+}
+
+static void object_type_loaded_observer(const char *name,
+ const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
+{
+ if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
+ && !reloaded) {
+ event_observed++;
+ }
+}
+
+static void object_type_reloaded_observer(const char *name,
+ const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
+{
+ if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
+ && reloaded) {
+ event_observed++;
+ }
+}
+
+AST_TEST_DEFINE(instance_observation)
+{
+ RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+ struct ast_sorcery_instance_observer observer = {
+ .wizard_mapped = wizard_mapped_observer,
+ .object_type_registered = object_type_registered_observer,
+ };
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "instance_observation";
+ info->category = "/main/sorcery/";
+ info->summary = "sorcery instance observation test";
+ info->description =
+ "Test observation of sorcery (instance)";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ /* Test instance load */
+ if (!(sorcery = ast_sorcery_open())) {
+ ast_test_status_update(test, "Failed to open a sorcery instance\n");
+ return AST_TEST_FAIL;
+ }
+ observer.instance_loading = instance_loaded_observer;
+ observer.instance_loaded = instance_loaded_observer;
+ ast_sorcery_instance_observer_add(sorcery, &observer);
+ event_observed = 0;
+ ast_sorcery_load(sorcery);
+ ast_test_validate(test, (event_observed == 2), "Instance loaded failed");
+ event_observed = 0;
+ ast_sorcery_reload(sorcery);
+ ast_test_validate(test, (event_observed == 0), "Instance reloaded failed");
+
+ /* Test instance reload */
+ ast_sorcery_instance_observer_remove(sorcery, &observer);
+ observer.instance_loading = instance_reloaded_observer;
+ observer.instance_loaded = instance_reloaded_observer;
+ ast_sorcery_instance_observer_add(sorcery, &observer);
+ event_observed = 0;
+ ast_sorcery_load(sorcery);
+ ast_test_validate(test, (event_observed == 0), "Instance loaded failed");
+ event_observed = 0;
+ ast_sorcery_reload(sorcery);
+ ast_test_validate(test, (event_observed == 2), "Instance reloaded failed");
+
+ /* Test wizard mapping */
+ event_observed = 0;
+ ast_sorcery_apply_default(sorcery, "test_object_type", "memory", "memwiz");
+ ast_test_validate(test, (event_observed == 1), "Wizard mapping failed");
+
+ /* Test object type register */
+ event_observed = 0;
+ ast_sorcery_internal_object_register(sorcery, "test_object_type",
+ test_sorcery_object_alloc, NULL, NULL);
+ ast_test_validate(test, (event_observed == 1), "Object type registered failed");
+
+ /* Test object type load */
+ ast_sorcery_instance_observer_remove(sorcery, &observer);
+ observer.object_type_loading = object_type_loaded_observer;
+ observer.object_type_loaded = object_type_loaded_observer;
+ ast_sorcery_instance_observer_add(sorcery, &observer);
+ event_observed = 0;
+ ast_sorcery_load_object(sorcery, "test_object_type");
+ ast_test_validate(test, (event_observed == 2), "Object type loaded failed");
+ event_observed = 0;
+ ast_sorcery_reload_object(sorcery, "test_object_type");
+ ast_test_validate(test, (event_observed == 0), "Object type reloaded failed");
+
+ /* Test object type reload */
+ ast_sorcery_instance_observer_remove(sorcery, &observer);
+ observer.object_type_loading = object_type_reloaded_observer;
+ observer.object_type_loaded = object_type_reloaded_observer;
+ ast_sorcery_instance_observer_add(sorcery, &observer);
+ event_observed = 0;
+ ast_sorcery_load_object(sorcery, "test_object_type");
+ ast_test_validate(test, (event_observed == 0), "Object type loaded failed");
+ event_observed = 0;
+ ast_sorcery_reload_object(sorcery, "test_object_type");
+ ast_test_validate(test, (event_observed == 2), "Object type reloaded failed");
+
+ ast_sorcery_instance_observer_remove(sorcery, &observer);
+ event_observed = 0;
+ ast_sorcery_apply_default(sorcery, "test_object_type", "memory", "memwiz");
+ ast_test_validate(test, (event_observed == 0), "Observer remove failed");
+
+ return AST_TEST_PASS;
+}
+
+static void wizard_loaded_observer(const char *name,
+ const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
+{
+ if (!strcmp(name, "test") && !strcmp(object_type, "test_object_type")
+ && !reloaded) {
+ event_observed++;
+ }
+}
+
+static void sorcery_test_load(void *data, const struct ast_sorcery *sorcery, const char *type)
+{
+ return;
+}
+
+static void wizard_reloaded_observer(const char *name,
+ const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
+{
+ if (!strcmp(name, "test") && !strcmp(object_type, "test_object_type")
+ && reloaded) {
+ event_observed++;
+ }
+}
+
+AST_TEST_DEFINE(wizard_observation)
+{
+ RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+ RAII_VAR(struct ast_sorcery_wizard *, wizard, &test_wizard, ast_sorcery_wizard_unregister);
+ struct ast_sorcery_wizard_observer observer = {
+ .wizard_loading = wizard_loaded_observer,
+ .wizard_loaded = wizard_loaded_observer,
+ };
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "wizard_observation";
+ info->category = "/main/sorcery/";
+ info->summary = "sorcery wizard observation test";
+ info->description =
+ "Test observation of sorcery (wizard)";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ wizard->load = sorcery_test_load;
+ wizard->reload = sorcery_test_load;
+
+ /* Test wizard observer remove and wizard unregister */
+ ast_sorcery_wizard_register(wizard);
+ ast_sorcery_wizard_observer_add(wizard, &observer);
+ ast_sorcery_wizard_observer_remove(wizard, &observer);
+ event_observed = 0;
+ ast_sorcery_wizard_unregister(wizard);
+ ast_test_validate(test, (event_observed == 0), "Wizard observer removed failed");
+
+ /* Setup for test loaded and reloaded */
+ if (!(sorcery = ast_sorcery_open())) {
+ ast_test_status_update(test, "Failed to open a sorcery instance\n");
+ return AST_TEST_FAIL;
+ }
+
+ ast_sorcery_wizard_register(wizard);
+ ast_sorcery_apply_default(sorcery, "test_object_type", "test", NULL);
[... 52 lines stripped ...]
More information about the asterisk-commits
mailing list