From 3fa4278a31d0f6f738b951c0d592941281aed196 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Fri, 25 Jan 2013 14:01:04 +0000 Subject: Merge the sorcery data access layer API. Sorcery is a unifying data access layer which provides a pluggable mechanism to allow object creation, retrieval, updating, and deletion using different backends (or wizards). This is a fancy way of saying "one interface to rule them all" where them is configuration, realtime, and anything else that comes along. Review: https://reviewboard.asterisk.org/r/2259/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@380069 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- include/asterisk/sorcery.h | 537 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 537 insertions(+) create mode 100644 include/asterisk/sorcery.h (limited to 'include/asterisk/sorcery.h') diff --git a/include/asterisk/sorcery.h b/include/asterisk/sorcery.h new file mode 100644 index 000000000..1a1042fbd --- /dev/null +++ b/include/asterisk/sorcery.h @@ -0,0 +1,537 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2012 - 2013, Digium, Inc. + * + * Joshua Colp + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * \brief Sorcery Data Access Layer API + * \author Joshua Colp + * \ref AstSorcery + */ + +/*! + * \page AstSorcery Data Access Layer API + * + * Sorcery is a unifying data access layer which utilizes the configuration framework, + * realtime, and astdb to allow object creation, retrieval, updating, and deletion. + * + * \par Initialization + * + * Usage of sorcery is accomplished by first opening a sorcery structure. This structure holds + * all information about the object types, object fields, and object mappings. All API functions + * require the sorcery structure to operate. When sorcery is no longer needed the structure can + * be unreferenced using \ref ast_sorcery_unref + * + * Once opened the sorcery structure must have object mappings applied to it. This maps the + * object types to their respective wizards (object storage modules). If the developer would like + * to allow the user to configure this using the sorcery.conf configuration file the + * \ref ast_sorcery_apply_config API call can be used to read in the configuration file and apply the + * mappings. If the storage of the object types are such that a default wizard can be used this can + * be applied using the \ref ast_sorcery_apply_default API call. Note that the default mappings will not + * override configured mappings. They are only used in the case where no configured mapping exists. + * + * Configuring object mappings implicitly creates a basic version of an object type. The object type + * must be fully registered, however, using the \ref ast_sorcery_object_type_register API call before any + * objects of the type can be allocated, created, or retrieved. + * + * Once the object type itself has been fully registered the individual fields within the object must + * be registered using the \ref ast_sorcery_object_field_register API call. Note that not all fields *need* + * be registered. Only fields that should be accessible using the sorcery API have to be registered. + * + * \par Creating Objects + * + * Before an object can be created within the sorcery API it must first be allocated using the + * \ref ast_sorcery_alloc API call. This allocates a new instance of the object, sets sorcery specific + * details, and applies default values to the object. A unique identifier can optionally be specified + * when allocating an object. If it is not provided one will be automatically generated. Allocating + * an object does not create it within any object storage mechanisms that are configured for the + * object type. Creation must explicitly be done using the \ref ast_sorcery_create API call. This API call + * passes the object to each configured object storage mechanism for the object type until one + * successfully persists the object. + * + * \par Retrieving Objects + * + * To retrieve a single object using its unique identifier the \ref ast_sorcery_retrieve_by_id API call + * can be used. + * + * To retrieve potentially multiple objects using specific fields the \ref ast_sorcery_retrieve_by_fields + * API call can be used. The behavior of this API call is controlled using different flags. If the + * AST_RETRIEVE_FLAG_MULTIPLE flag is used a container will be returned which contains all matching objects. + * To retrieve all objects the AST_RETRIEVE_FLAG_ALL flag can be specified. Note that when specifying this flag + * you do not need to pass any fields. + * + * Both API calls return shared objects. Modification of the object can not occur until it has been copied. + * + * \par Updating Objects + * + * As retrieved objects may be shared the first step to updating the object with new details is creating a + * copy using the \ref ast_sorcery_copy API call. This will return a new object which is specific to the caller. + * Any field within the object may be modified as needed. Once changes are done the changes can be committed + * using the \ref ast_sorcery_update API call. Note that as the copied object is specific to the caller it must + * be unreferenced after use. + * + * \par Deleting Objects + * + * To delete an object simply call the \ref ast_sorcery_delete API call with an object retrieved using the + * ast_sorcery_retrieve_by_* API calls or a copy returned from \ref ast_sorcery_copy. + */ + +#ifndef _ASTERISK_SORCERY_H +#define _ASTERISK_SORCERY_H + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include "asterisk/config_options.h" +#include "asterisk/uuid.h" + +/*! \brief Maximum size of an object type */ +#define MAX_OBJECT_TYPE 64 + +/*! + * \brief Retrieval flags + */ +enum ast_sorcery_retrieve_flags { + /*! \brief Default retrieval flags */ + AST_RETRIEVE_FLAG_DEFAULT = 0, + + /*! \brief Return all matching objects */ + AST_RETRIEVE_FLAG_MULTIPLE = (1 << 0), + + /*! \brief Perform no matching, return all objects */ + AST_RETRIEVE_FLAG_ALL = (1 << 1), +}; + +/*! \brief Forward declaration for the sorcery main structure */ +struct ast_sorcery; + +/*! + * \brief A callback function for translating a value into a string + * + * \param obj Object to get value from + * \param args Where the field is + * \param buf Pointer to the buffer that the handler has created which contains the field value + * + * \retval 0 success + * \retval -1 failure + */ +typedef int (*sorcery_field_handler)(const void *obj, const intptr_t *args, char **buf); + +/*! + * \brief A callback function for performing a transformation on an object set + * + * \param set The existing object set + * + * \retval non-NULL new object set if changed + * \retval NULL if no changes present + * + * \note The returned ast_variable list must be *new*. You can not return the input set. + */ +typedef struct ast_variable *(*sorcery_transform_handler)(struct ast_variable *set); + +/*! + * \brief A callback function for when an object set is successfully applied to an object + * + * \param sorcery Sorcery structure in use + * \param obj The object itself + */ +typedef void (*sorcery_apply_handler)(const struct ast_sorcery *sorcery, void *obj); + +/*! \brief Interface for a sorcery wizard */ +struct ast_sorcery_wizard { + /*! \brief Name of the wizard */ + const char *name; + + /*! \brief Pointer to the Asterisk module this wizard is implemented by */ + struct ast_module *module; + + /*! \brief Callback for opening a wizard */ + void *(*open)(const char *data); + + /*! \brief Optional callback for loading persistent objects */ + void (*load)(void *data, const struct ast_sorcery *sorcery, const char *type); + + /*! \brief Optional callback for reloading persistent objects */ + void (*reload)(void *data, const struct ast_sorcery *sorcery, const char *type); + + /*! \brief Callback for creating an object */ + int (*create)(void *data, void *object); + + /*! \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 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); + + /*! \brief Optional callback for retrieving multiple objects using some optional field criteria */ + void (*retrieve_multiple)(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields); + + /*! \brief Callback for updating an object */ + int (*update)(void *data, void *object); + + /*! \brief Callback for deleting an object */ + int (*delete)(void *data, void *object); + + /*! \brief Callback for closing a wizard */ + void (*close)(void *data); +}; + +/*! \brief Structure which contains details about a sorcery object */ +struct ast_sorcery_object_details { + /*! \brief Unique identifier of this object */ + char id[AST_UUID_STR_LEN]; + + /*! \brief Type of object */ + char type[MAX_OBJECT_TYPE]; +}; + +/*! \brief Macro which must be used at the beginning of each sorcery capable object */ +#define SORCERY_OBJECT(details) \ +struct { \ + struct ast_sorcery_object_details details; \ +} \ + +/*! + * \brief Initialize the sorcery API + * + * \retval 0 success + * \retval -1 failure + */ +int ast_sorcery_init(void); + +/*! + * \brief Register a sorcery wizard + * + * \param interface Pointer to a wizard interface + * \param module Pointer to the module implementing the interface + * + * \retval 0 success + * \retval -1 failure + */ +int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module); + +/*! + * \brief See \ref __ast_sorcery_wizard_register() + */ +#define ast_sorcery_wizard_register(interface) __ast_sorcery_wizard_register(interface, ast_module_info ? ast_module_info->self : NULL) + +/*! + * \brief Unregister a sorcery wizard + * + * \param interface Pointer to the wizard interface + * + * \retval 0 success + * \retval -1 failure + */ +int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface); + +/*! + * \brief Open a new sorcery structure + * + * \retval non-NULL success + * \retval NULL if allocation failed + */ +struct ast_sorcery *ast_sorcery_open(void); + +/*! + * \brief Apply configured wizard mappings + * + * \param sorcery Pointer to a sorcery structure + * \param name Name of the category to use within the configuration file, normally the module name + * + * \retval 0 success + * \retval -1 failure + */ +int ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name); + +/*! + * \brief Apply default object wizard mappings + * + * \param sorcery Pointer to a sorcery structure + * \param type Type of object to apply to + * \param name Name of the wizard to use + * \param data Data to be passed to wizard + * + * \retval 0 success + * \retval -1 failure + * + * \note This should be called *after* applying configuration sourced mappings + * + * \note Only a single default can exist per object type + */ +int ast_sorcery_apply_default(struct ast_sorcery *sorcery, const char *type, const char *name, const char *data); + +/*! + * \brief Register an object type + * + * \param sorcery Pointer to a sorcery structure + * \param type Type of object + * \param alloc Required object allocation callback + * \param transform Optional transformation callback + * \param apply Optional object set apply callback + * + * \retval 0 success + * \retval -1 failure + */ +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); + +/*! + * \brief Register a field within an object + * + * \param sorcery Pointer to a sorcery structure + * \param type Type of object + * \param name Name of the field + * \param default_val Default value of the field + * \param opt_type Option type + * \param flags Option type specific flags + * + * \retval 0 success + * \retval -1 failure + */ +int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char *type, const char *name, const char *default_val, enum aco_option_type opt_type, + aco_option_handler config_handler, sorcery_field_handler sorcery_handler, unsigned int flags, size_t argc, ...); + +/*! + * \brief Register a field within an object + * + * \param sorcery Pointer to a sorcery structure + * \param type Type of object + * \param name Name of the field + * \param default_val Default value of the field + * \param opt_type Option type + * \param flags Option type specific flags + * + * \retval 0 success + * \retval -1 failure + */ +#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags, ...) \ + __ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, NULL, NULL, flags, VA_NARGS(__VA_ARGS__), __VA_ARGS__) + +/*! + * \brief Register a field within an object with custom handlers + * + * \param sorcery Pointer to a sorcery structure + * \param type Type of object + * \param name Name of the field + * \param default_val Default value of the field + * \param config_handler Custom configuration handler + * \param sorcery_handler Custom sorcery handler + * \param flags Option type specific flags + * + * \retval 0 success + * \retval -1 failure + */ +#define ast_sorcery_object_field_register_custom(sorcery, type, name, default_val, config_handler, sorcery_handler, flags, ...) \ + __ast_sorcery_object_field_register(sorcery, type, name, default_val, OPT_CUSTOM_T, config_handler, sorcery_handler, flags, VA_NARGS(__VA_ARGS__), __VA_ARGS__); + +/*! + * \brief Inform any wizards to load persistent objects + * + * \param sorcery Pointer to a sorcery structure + */ +void ast_sorcery_load(const struct ast_sorcery *sorcery); + +/*! + * \brief Inform any wizards to reload persistent objects + * + * \param sorcery Pointer to a sorcery structure + */ +void ast_sorcery_reload(const struct ast_sorcery *sorcery); + +/*! + * \brief Increase the reference count of a sorcery structure + * + * \param sorcery Pointer to a sorcery structure + */ +void ast_sorcery_ref(struct ast_sorcery *sorcery); + +/*! + * \brief Create an object set (KVP list) for an object + * + * \param sorcery Pointer to a sorcery structure + * \param object Pointer to a sorcery object + * + * \retval non-NULL success + * \retval NULL if error occurred + * + * \note The returned ast_variable list must be destroyed using ast_variables_destroy + */ +struct ast_variable *ast_sorcery_objectset_create(const struct ast_sorcery *sorcery, const void *object); + +/*! + * \brief Apply an object set (KVP list) to an object + * + * \param sorcery Pointer to a sorcery structure + * \param object Pointer to a sorcery object + * \param objectset Object set itself + * + * \retval 0 success + * \retval -1 failure + * + * \note This operation is *not* atomic. If this fails it is possible for the object to be left with a partially + * applied object set. + */ +int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object, struct ast_variable *objectset); + +/*! + * \brief Create a changeset given two object sets + * + * \param original Original object set + * \param modified Modified object set + * \param changes Pointer to hold any changes between the object sets + * + * \retval 0 success + * \retval -1 failure + * + * \note The returned ast_variable list must be destroyed using ast_variables_destroy + */ +int ast_sorcery_changeset_create(const struct ast_variable *original, const struct ast_variable *modified, struct ast_variable **changes); + +/*! + * \brief Allocate an object + * + * \param sorcery Pointer to a sorcery structure + * \param type Type of object to allocate + * \param id Optional unique identifier, if none is provided one will be generated + * + * \retval non-NULL success + * \retval NULL failure + */ +void *ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id); + +/*! + * \brief Create a copy of an object + * + * \param sorcery Pointer to a sorcery structure + * \param object Existing object + * + * \retval non-NULL success + * \retval NULL failure + */ +void *ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object); + +/*! + * \brief Create a changeset of two objects + * + * \param sorcery Pointer to a sorcery structure + * \param original Original object + * \param modified Modified object + * \param changes Pointer which will be populated with changes if any exist + * + * \retval 0 success + * \retval -1 failure + * + * \note The returned ast_variable list must be destroyed using ast_variables_destroy + * + * \note While the objects must be of the same type they do not have to be the same object + */ +int ast_sorcery_diff(const struct ast_sorcery *sorcery, const void *original, const void *modified, struct ast_variable **changes); + +/*! + * \brief Create and potentially persist an object using an available wizard + * + * \param sorcery Pointer to a sorcery structure + * \param object Pointer to a sorcery object + * + * \retval 0 success + * \retval -1 failure + */ +int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object); + +/*! + * \brief Retrieve an object using its unique identifier + * + * \param sorcery Pointer to a sorcery structure + * \param type Type of object to retrieve + * \param id Unique object identifier + * + * \retval non-NULL if found + * \retval NULL if not found + */ +void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id); + +/*! + * \brief Retrieve an object or multiple objects using specific fields + * + * \param sorcery Pointer to a sorcery structure + * \param type Type of object to retrieve + * \param flags Flags to control behavior + * \param fields Optional jbject fields and values to match against + * + * \retval non-NULL if found + * \retval NULL if not found + * + * \note If the AST_RETRIEVE_FLAG_MULTIPLE flag is specified the returned value will be an + * ao2_container that must be unreferenced after use. + * + * \note If the AST_RETRIEVE_FLAG_ALL flag is used you may omit fields to retrieve all objects + * of the given type. + */ +void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields); + +/*! + * \brief Update an object + * + * \param sorcery Pointer to a sorcery structure + * \param object Pointer to a sorcery object + * + * \retval 0 success + * \retval -1 failure + */ +int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object); + +/*! + * \brief Delete an object + * + * \param sorcery Pointer to a sorcery structure + * \param object Pointer to a sorcery object + * + * \retval 0 success + * \retval -1 failure + */ +int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object); + +/*! + * \brief Decrease the reference count of a sorcery structure + * + * \param sorcery Pointer to a sorcery structure + */ +void ast_sorcery_unref(struct ast_sorcery *sorcery); + +/*! + * \brief Get the unique identifier of a sorcery object + * + * \param object Pointer to a sorcery object + * + * \retval unique identifier + */ +const char *ast_sorcery_object_get_id(const void *object); + +/*! + * \brief Get the type of a sorcery object + * + * \param object Pointer to a sorcery object + * + * \retval type of object + */ +const char *ast_sorcery_object_get_type(const void *object); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* _ASTERISK_SORCERY_H */ -- cgit v1.2.3