asterisk_processor.py

Go to the documentation of this file.
00001 #
00002 # Asterisk -- An open source telephony toolkit.
00003 #
00004 # Copyright (C) 2013, Digium, Inc.
00005 #
00006 # David M. Lee, II <dlee@digium.com>
00007 #
00008 # See http://www.asterisk.org for more information about
00009 # the Asterisk project. Please do not directly contact
00010 # any of the maintainers of this project for assistance;
00011 # the project provides a web site, mailing lists and IRC
00012 # channels for your use.
00013 #
00014 # This program is free software, distributed under the terms of
00015 # the GNU General Public License Version 2. See the LICENSE file
00016 # at the top of the source tree.
00017 #
00018 
00019 """Implementation of SwaggerPostProcessor which adds fields needed to generate
00020 Asterisk RESTful HTTP binding code.
00021 """
00022 
00023 import re
00024 
00025 from swagger_model import *
00026 
00027 try:
00028     from collections import OrderedDict
00029 except ImportError:
00030     from odict import OrderedDict
00031 
00032 
00033 def simple_name(name):
00034     """Removes the {markers} from a path segement.
00035 
00036     @param name: Swagger path segement, with {pathVar} markers.
00037     """
00038     if name.startswith('{') and name.endswith('}'):
00039         return name[1:-1]
00040     return name
00041 
00042 
00043 def wikify(str):
00044     """Escapes a string for the wiki.
00045 
00046     @param str: String to escape
00047     """
00048     return re.sub(r'([{}\[\]])', r'\\\1', str)
00049 
00050 
00051 def snakify(name):
00052     """Helper to take a camelCase or dash-seperated name and make it
00053     snake_case.
00054     """
00055     r = ''
00056     prior_lower = False
00057     for c in name:
00058         if c.isupper() and prior_lower:
00059             r += "_"
00060         if c is '-':
00061             c = '_'
00062         prior_lower = c.islower()
00063         r += c.lower()
00064     return r
00065 
00066 
00067 class PathSegment(Stringify):
00068     """Tree representation of a Swagger API declaration.
00069     """
00070     def __init__(self, name, parent):
00071         """Ctor.
00072 
00073         @param name: Name of this path segment. May have {pathVar} markers.
00074         @param parent: Parent PathSegment.
00075         """
00076         #: Segment name, with {pathVar} markers removed
00077         self.name = simple_name(name)
00078         #: True if segment is a {pathVar}, else None.
00079         self.is_wildcard = None
00080         #: Underscore seperated name all ancestor segments
00081         self.full_name = None
00082         #: Dictionary of child PathSegements
00083         self.__children = OrderedDict()
00084         #: List of operations on this segement
00085         self.operations = []
00086 
00087         if self.name != name:
00088             self.is_wildcard = True
00089 
00090         if not self.name:
00091             assert(not parent)
00092             self.full_name = ''
00093         if not parent or not parent.name:
00094             self.full_name = name
00095         else:
00096             self.full_name = "%s_%s" % (parent.full_name, self.name)
00097 
00098     def get_child(self, path):
00099         """Walks decendents to get path, creating it if necessary.
00100 
00101         @param path: List of path names.
00102         @return: PageSegment corresponding to path.
00103         """
00104         assert simple_name(path[0]) == self.name
00105         if (len(path) == 1):
00106             return self
00107         child = self.__children.get(path[1])
00108         if not child:
00109             child = PathSegment(path[1], self)
00110             self.__children[path[1]] = child
00111         return child.get_child(path[1:])
00112 
00113     def children(self):
00114         """Gets list of children.
00115         """
00116         return self.__children.values()
00117 
00118     def num_children(self):
00119         """Gets count of children.
00120         """
00121         return len(self.__children)
00122 
00123 
00124 class AsteriskProcessor(SwaggerPostProcessor):
00125     """A SwaggerPostProcessor which adds fields needed to generate Asterisk
00126     RESTful HTTP binding code.
00127     """
00128 
00129     #: How Swagger types map to C.
00130     type_mapping = {
00131         'string': 'const char *',
00132         'boolean': 'int',
00133         'number': 'int',
00134         'int': 'int',
00135         'long': 'long',
00136         'double': 'double',
00137         'float': 'float',
00138     }
00139 
00140     #: String conversion functions for string to C type.
00141     convert_mapping = {
00142         'string': '',
00143         'int': 'atoi',
00144         'long': 'atol',
00145         'double': 'atof',
00146         'boolean': 'ast_true',
00147     }
00148 
00149     #: JSON conversion functions
00150     json_convert_mapping = {
00151         'string': 'ast_json_string_get',
00152         'int': 'ast_json_integer_get',
00153         'long': 'ast_json_integer_get',
00154         'double': 'ast_json_real_get',
00155         'boolean': 'ast_json_is_true',
00156     }
00157 
00158     def __init__(self, wiki_prefix):
00159         self.wiki_prefix = wiki_prefix
00160 
00161     def process_resource_api(self, resource_api, context):
00162         resource_api.wiki_prefix = self.wiki_prefix
00163         # Derive a resource name from the API declaration's filename
00164         resource_api.name = re.sub('\..*', '',
00165                                    os.path.basename(resource_api.path))
00166         # Now in all caps, for include guard
00167         resource_api.name_caps = resource_api.name.upper()
00168         resource_api.name_title = resource_api.name.capitalize()
00169         resource_api.c_name = snakify(resource_api.name)
00170         # Construct the PathSegement tree for the API.
00171         if resource_api.api_declaration:
00172             resource_api.root_path = PathSegment('', None)
00173             for api in resource_api.api_declaration.apis:
00174                 segment = resource_api.root_path.get_child(api.path.split('/'))
00175                 for operation in api.operations:
00176                     segment.operations.append(operation)
00177                 api.full_name = segment.full_name
00178 
00179             # Since every API path should start with /[resource], root should
00180             # have exactly one child.
00181             if resource_api.root_path.num_children() != 1:
00182                 raise SwaggerError(
00183                     "Should not mix resources in one API declaration", context)
00184             # root_path isn't needed any more
00185             resource_api.root_path = resource_api.root_path.children()[0]
00186             if resource_api.name != resource_api.root_path.name:
00187                 raise SwaggerError(
00188                     "API declaration name should match", context)
00189             resource_api.root_full_name = resource_api.root_path.full_name
00190 
00191     def process_api(self, api, context):
00192         api.wiki_path = wikify(api.path)
00193 
00194     def process_operation(self, operation, context):
00195         # Nicknames are camelCase, Asterisk coding is snake case
00196         operation.c_nickname = snakify(operation.nickname)
00197         operation.c_http_method = 'AST_HTTP_' + operation.http_method
00198         if not operation.summary.endswith("."):
00199             raise SwaggerError("Summary should end with .", context)
00200         operation.wiki_summary = wikify(operation.summary or "")
00201         operation.wiki_notes = wikify(operation.notes or "")
00202         operation.parse_body = (operation.body_parameter or operation.has_query_parameters) and True
00203 
00204     def process_parameter(self, parameter, context):
00205         if parameter.param_type == 'body':
00206        parameter.is_body_parameter = True;
00207             parameter.c_data_type = 'struct ast_json *'
00208         else:
00209        parameter.is_body_parameter = False;
00210             if not parameter.data_type in self.type_mapping:
00211                 raise SwaggerError(
00212                     "Invalid parameter type %s" % parameter.data_type, context)
00213             # Type conversions
00214             parameter.c_data_type = self.type_mapping[parameter.data_type]
00215             parameter.c_convert = self.convert_mapping[parameter.data_type]
00216             parameter.json_convert = self.json_convert_mapping[parameter.data_type]
00217 
00218         # Parameter names are camelcase, Asterisk convention is snake case
00219         parameter.c_name = snakify(parameter.name)
00220         # You shouldn't put a space between 'char *' and the variable
00221         if parameter.c_data_type.endswith('*'):
00222             parameter.c_space = ''
00223         else:
00224             parameter.c_space = ' '
00225         parameter.wiki_description = wikify(parameter.description)
00226         if parameter.allowable_values:
00227             parameter.wiki_allowable_values = parameter.allowable_values.to_wiki()
00228         else:
00229             parameter.wiki_allowable_values = None
00230 
00231     def process_model(self, model, context):
00232         model.description_dox = model.description.replace('\n', '\n * ')
00233         model.description_dox = re.sub(' *\n', '\n', model.description_dox)
00234         model.wiki_description = wikify(model.description)
00235         model.c_id = snakify(model.id)
00236         return model
00237 
00238     def process_property(self, prop, context):
00239         if "-" in prop.name:
00240             raise SwaggerError("Property names cannot have dashes", context)
00241         if prop.name != prop.name.lower():
00242             raise SwaggerError("Property name should be all lowercase",
00243                                context)
00244         prop.wiki_description = wikify(prop.description)
00245 
00246     def process_type(self, swagger_type, context):
00247         swagger_type.c_name = snakify(swagger_type.name)
00248         swagger_type.c_singular_name = snakify(swagger_type.singular_name)
00249         swagger_type.wiki_name = wikify(swagger_type.name)

Generated on Thu Apr 16 06:27:14 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6