summaryrefslogtreecommitdiff
path: root/main/sorcery.c
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2013-06-22 14:26:25 +0000
committerJoshua Colp <jcolp@digium.com>2013-06-22 14:26:25 +0000
commita330d0867e3155e34ecbfd23a84fe6e7ebf51469 (patch)
treed19cbb217482b0dc2952afe2495d59b868d1ff82 /main/sorcery.c
parent77002bc377f19ea11e60732c486b6ef371688773 (diff)
Make sorcery details opaque and add extended fields.
Sorcery specific object information is now opaque and allocated with the object. This means that modules do not need to be recompiled if the sorcery specific part is changed. It also means that sorcery can store additional information on objects and ensure it is freed or the reference count decreased when the object goes away. To facilitate the above a generic sorcery allocator function has been added which also ensures that allocated objects do not have a lock. Extended fields have been added thanks to all of the above which allows specific fields to be marked as extended, and thus simply stored as-is within the object. Type safety is *NOT* enforced on these fields. A consumer of them has to query and ultimately perform their own safety check. What does this mean? Extra modules can extend already defined structures without having to modify them. Tests have also been included to verify extended field functionality. Review: https://reviewboard.asterisk.org/r/2585/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@392586 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/sorcery.c')
-rw-r--r--main/sorcery.c136
1 files changed, 120 insertions, 16 deletions
diff --git a/main/sorcery.c b/main/sorcery.c
index 99e4c5586..cf4cd0213 100644
--- a/main/sorcery.c
+++ b/main/sorcery.c
@@ -58,6 +58,21 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
/*! \brief Thread pool for observers */
static struct ast_threadpool *threadpool;
+/*! \brief Structure for internal sorcery object information */
+struct ast_sorcery_object {
+ /*! \brief Unique identifier of this object */
+ char id[AST_UUID_STR_LEN];
+
+ /*! \brief Type of object */
+ char type[MAX_OBJECT_TYPE];
+
+ /*! \brief Optional object destructor */
+ ao2_destructor_fn destructor;
+
+ /*! \brief Extended object fields */
+ struct ast_variable *extended;
+};
+
/*! \brief Structure for registered object type */
struct ast_sorcery_object_type {
/*! \brief Unique name of the object type */
@@ -525,6 +540,24 @@ int __ast_sorcery_apply_default(struct ast_sorcery *sorcery, const char *type, c
return 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)
+{
+ return ast_sorcery_object_set_extended(obj, var->name, var->value);
+}
+
+static int sorcery_extended_fields_handler(const void *obj, struct ast_variable **fields)
+{
+ const struct ast_sorcery_object_details *details = obj;
+
+ if (details->object->extended) {
+ *fields = ast_variables_dup(details->object->extended);
+ } else {
+ *fields = NULL;
+ }
+
+ return 0;
+}
+
int ast_sorcery_object_register(struct ast_sorcery *sorcery, const char *type, aco_type_item_alloc alloc, sorcery_transform_handler transform, sorcery_apply_handler apply)
{
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
@@ -547,6 +580,10 @@ int ast_sorcery_object_register(struct ast_sorcery *sorcery, const char *type, a
return -1;
}
+ if (ast_sorcery_object_fields_register(sorcery, type, "^@", sorcery_extended_config_handler, sorcery_extended_fields_handler)) {
+ return -1;
+ }
+
return 0;
}
@@ -784,7 +821,7 @@ void ast_sorcery_ref(struct ast_sorcery *sorcery)
struct ast_variable *ast_sorcery_objectset_create(const struct ast_sorcery *sorcery, const void *object)
{
const struct ast_sorcery_object_details *details = object;
- RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->type, OBJ_KEY), ao2_cleanup);
+ RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
struct ao2_iterator i;
struct ast_sorcery_object_field *object_field;
struct ast_variable *fields = NULL;
@@ -816,7 +853,7 @@ struct ast_variable *ast_sorcery_objectset_create(const struct ast_sorcery *sorc
continue;
}
- if (!res) {
+ if (!res && tmp) {
tmp->next = fields;
fields = tmp;
}
@@ -836,7 +873,7 @@ struct ast_variable *ast_sorcery_objectset_create(const struct ast_sorcery *sorc
struct ast_json *ast_sorcery_objectset_json_create(const struct ast_sorcery *sorcery, const void *object)
{
const struct ast_sorcery_object_details *details = object;
- RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->type, OBJ_KEY), ao2_cleanup);
+ RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
struct ao2_iterator i;
struct ast_sorcery_object_field *object_field;
struct ast_json *json = ast_json_object_create();
@@ -898,7 +935,7 @@ struct ast_json *ast_sorcery_objectset_json_create(const struct ast_sorcery *sor
int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object, struct ast_variable *objectset)
{
const struct ast_sorcery_object_details *details = object;
- RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->type, OBJ_KEY), ao2_cleanup);
+ RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
RAII_VAR(struct ast_variable *, transformed, NULL, ast_variables_destroy);
struct ast_variable *field;
int res = 0;
@@ -914,7 +951,7 @@ int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object,
}
for (; field; field = field->next) {
- if ((res = aco_process_var(&object_type->type, details->id, field, object))) {
+ if ((res = aco_process_var(&object_type->type, details->object->id, field, object))) {
break;
}
}
@@ -977,6 +1014,32 @@ int ast_sorcery_changeset_create(const struct ast_variable *original, const stru
return res;
}
+static void sorcery_object_destructor(void *object)
+{
+ struct ast_sorcery_object_details *details = object;
+
+ if (details->object->destructor) {
+ details->object->destructor(object);
+ }
+
+ ast_variables_destroy(details->object->extended);
+}
+
+void *ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
+{
+ void *object = ao2_alloc_options(size + sizeof(struct ast_sorcery_object), sorcery_object_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
+ struct ast_sorcery_object_details *details = object;
+
+ if (!object) {
+ return NULL;
+ }
+
+ details->object = object + size;
+ details->object->destructor = destructor;
+
+ return object;
+}
+
void *ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
{
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
@@ -988,12 +1051,12 @@ void *ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, con
}
if (ast_strlen_zero(id)) {
- ast_uuid_generate_str(details->id, sizeof(details->id));
+ ast_uuid_generate_str(details->object->id, sizeof(details->object->id));
} else {
- ast_copy_string(details->id, id, sizeof(details->id));
+ ast_copy_string(details->object->id, id, sizeof(details->object->id));
}
- ast_copy_string(details->type, type, sizeof(details->type));
+ ast_copy_string(details->object->type, type, sizeof(details->object->type));
if (aco_set_defaults(&object_type->type, id, details)) {
ao2_ref(details, -1);
@@ -1006,8 +1069,8 @@ void *ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, con
void *ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
{
const struct ast_sorcery_object_details *details = object;
- RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->type, OBJ_KEY), ao2_cleanup);
- struct ast_sorcery_object_details *copy = ast_sorcery_alloc(sorcery, details->type, details->id);
+ RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
+ struct ast_sorcery_object_details *copy = ast_sorcery_alloc(sorcery, details->object->type, details->object->id);
RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy);
int res = 0;
@@ -1120,7 +1183,6 @@ void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const ch
unsigned int cached = 0;
if (!object_type) {
- ast_log(LOG_NOTICE, "Can't find object type '%s'\n", type);
return NULL;
}
@@ -1222,7 +1284,7 @@ static int sorcery_observers_notify_create(void *data)
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
{
const struct ast_sorcery_object_details *details = object;
- RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->type, OBJ_KEY), ao2_cleanup);
+ RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
struct sorcery_details sdetails = {
.sorcery = sorcery,
@@ -1281,7 +1343,7 @@ static int sorcery_wizard_update(void *obj, void *arg, int flags)
int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
{
const struct ast_sorcery_object_details *details = object;
- RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->type, OBJ_KEY), ao2_cleanup);
+ RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
struct sorcery_details sdetails = {
.sorcery = sorcery,
@@ -1340,7 +1402,7 @@ static int sorcery_wizard_delete(void *obj, void *arg, int flags)
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
{
const struct ast_sorcery_object_details *details = object;
- RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->type, OBJ_KEY), ao2_cleanup);
+ RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
struct sorcery_details sdetails = {
.sorcery = sorcery,
@@ -1371,13 +1433,55 @@ void ast_sorcery_unref(struct ast_sorcery *sorcery)
const char *ast_sorcery_object_get_id(const void *object)
{
const struct ast_sorcery_object_details *details = object;
- return details->id;
+ return details->object->id;
}
const char *ast_sorcery_object_get_type(const void *object)
{
const struct ast_sorcery_object_details *details = object;
- return details->type;
+ return details->object->type;
+}
+
+const char *ast_sorcery_object_get_extended(const void *object, const char *name)
+{
+ const struct ast_sorcery_object_details *details = object;
+ struct ast_variable *field;
+
+ for (field = details->object->extended; field; field = field->next) {
+ if (!strcmp(field->name + 1, name)) {
+ return field->value;
+ }
+ }
+
+ return NULL;
+}
+
+int ast_sorcery_object_set_extended(const void *object, const char *name, const char *value)
+{
+ RAII_VAR(struct ast_variable *, field, NULL, ast_variables_destroy);
+ struct ast_variable *extended = ast_variable_new(name, value, ""), *previous = NULL;
+ const struct ast_sorcery_object_details *details = object;
+
+ if (!extended) {
+ return -1;
+ }
+
+ for (field = details->object->extended; field; previous = field, field = field->next) {
+ if (!strcmp(field->name, name)) {
+ if (previous) {
+ previous->next = field->next;
+ } else {
+ details->object->extended = field->next;
+ }
+ field->next = NULL;
+ break;
+ }
+ }
+
+ extended->next = details->object->extended;
+ details->object->extended = extended;
+
+ return 0;
}
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)