def __init__(self, stmt, path=None, package=None, src=None, ctx=None, ns='', prefix_name='', yang_types=None, parent=None): """Constructor. stmt -- A statement (sub)tree, parsed from a YANG model path -- Full path to where the class should be written package -- Name of Java package src -- Filename of parsed yang module, or the module name and revision if filename is unknown ctx -- Context used to fetch option parameters ns -- The XML namespace of the module prefix_name -- The module prefix yang_types -- An instance of the YangType class parent -- ClassGenerator to copy arguments that were not supplied from (if applicable) """ self.stmt = stmt self.path = path self.package = None if package is None else package.replace(os.sep, '.') self.src = src self.ctx = ctx self.ns = ns self.prefix_name = prefix_name self.yang_types = yang_types self.n = util.normalize(stmt.arg) self.n2 = util.camelize(stmt.arg) if stmt.keyword in context.module_stmts: self.filename = util.schema_class(util.normalize(util.search_one(stmt, 'prefix').arg)) + '.java' self.filename_visitor = util.visitor_class((util.normalize(util.search_one(stmt, 'prefix').arg))) + '.java' else: self.filename = self.n + '.java' self.filename_visitor = util.visitor_class(self.n) + '.java' if yang_types is None: self.yang_types = YangType() if parent is not None: for attr in ('package', 'src', 'ctx', 'path', 'ns', 'prefix_name', 'yang_types'): if getattr(self, attr) is None: setattr(self, attr, getattr(parent, attr)) module = util.get_module(stmt) if self.ctx.rootpkg: self.rootpkg = '.'.join([self.ctx.rootpkg.replace(os.sep, '.'), util.camelize(module.arg)]) else: self.rootpkg = util.camelize(module.arg) else: self.rootpkg = package
def toFieldName(name, isStatic=False, isApiName = False): ''' format field name to match java rules ''' # replace - with _ e.g. created-at => created_at name = name.replace('-', '_') # if it's all uppper case, do nothing if util.isAllUpperCase(name): return name # camelize (lower first character) the variable name # pet_id => petId name = util.camelize(name, True) if isStatic: # uppercase all characters with _ divider # pet_id => PET_ID name = re.sub(r'([A-Z])', r'_\1', name).upper() if isApiName: name = re.sub(r'{([^}]*)}', r'_\1', name) # for reserved word or word starting with number, append _ if name in reservedWords or name[0].isdigit(): name = escapeReservedWord(name) return name
def toApiMethodName(httpMethod, path): ''' use the api http method + path to generate a java api method name e.g. GET /user/favorite/{favorite_id}/tag => getUserFavoriteTag ''' result = util.camelize(path) result = re.sub(r'{([^}]*)}', '', result) #parts = result.split('{') return str(httpMethod).lower() + result
def getTagByPath(path): ''' when path doesn't have a tag. generate one by the path root e.g. /product/info => tag = Product ''' path = re.sub(r'/{1,}', '', path, 1) if '/' in path: parts = path.split('/') path = parts[0] return util.camelize(path)
def toClassName(name): ''' format class name to match java rules ''' # model name cannot use reserved keyword, e.g. return if name in reservedWords: raise RuntimeError('%s (reserved word) cannot be used as a model name' % name) # camelize the model name # phone_number => PhoneNumber return util.camelize(name)
def _find_class_for(cls, element_name=None, class_name=None, create_missing=True): """Look in the parent modules for classes matching the element name. One or both of element/class name must be specified. Args: element_name: The name of the element type. class_name: The class name of the element type. create_missing: Whether classes should be auto-created if no existing match is found. Returns: A Resource class. """ if not element_name and not class_name: raise Error('One of element_name,class_name must be specified.') elif not element_name: element_name = util.underscore(class_name) elif not class_name: class_name = util.camelize(element_name) module_path = cls.__module__.split('.') for depth in range(len(module_path), 0, -1): try: __import__('.'.join(module_path[:depth])) module = sys.modules['.'.join(module_path[:depth])] except ImportError: continue try: klass = getattr(module, class_name) return klass except AttributeError: try: __import__('.'.join([module.__name__, element_name])) submodule = sys.modules['.'.join( [module.__name__, element_name])] except ImportError: continue try: klass = getattr(submodule, class_name) return klass except AttributeError: continue # If we made it this far, no such class was found if create_missing: return new.classobj(class_name, (cls, ), {'__module__': cls.__module__})
def _find_class_for(cls, element_name=None, class_name=None, create_missing=True): """Look in the parent modules for classes matching the element name. One or both of element/class name must be specified. Args: element_name: The name of the element type. class_name: The class name of the element type. create_missing: Whether classes should be auto-created if no existing match is found. Returns: A Resource class. """ if not element_name and not class_name: raise Error('One of element_name,class_name must be specified.') elif not element_name: element_name = util.underscore(class_name) elif not class_name: class_name = util.camelize(element_name) module_path = cls.__module__.split('.') for depth in range(len(module_path), 0, -1): try: __import__('.'.join(module_path[:depth])) module = sys.modules['.'.join(module_path[:depth])] except ImportError: continue try: klass = getattr(module, class_name) return klass except AttributeError: try: __import__('.'.join([module.__name__, element_name])) submodule = sys.modules['.'.join([module.__name__, element_name])] except ImportError: continue try: klass = getattr(submodule, class_name) return klass except AttributeError: continue # If we made it this far, no such class was found if create_missing: return new.classobj(class_name, (cls,), {'__module__': cls.__module__})
def filter_camel_case(content, query_dict={}): """Ensures the response field names are consistently formatted in snake case if camel_case=false is present in the url query parameters. Otherwise the default camel case will be forced. :param response_data: dict|list :param query_dict: Dict :return: dict|None """ camel = "true" if query_dict.has_key("camelCase"): camel = query_dict.get("camelCase", "true") elif query_dict.has_key("camel_case"): camel = query_dict.get("camel_case", "true") if camel.lower() == "false": return underscoreize(content) else: return camelize(content)
def refToClassName(ref, needSimple=False): ''' convert a ref string to java class name ''' try: refType, refName = util.parseSwaggerRef(ref) except RuntimeError: print('"%s" is not a swagger reference' % ref) return ref prefix = '' if refType == 'definitions': # models prefix = modelPackage location = refName.split('/') result = prefix if len(location) > 0: location[-1] = util.camelize(location[-1]) for l in location: result += '.' + l # simple class name if needSimple: result = result.split('.')[-1] return result
def toSetter(name): ''' format setter name to match java rules ''' return 'set' + util.camelize(name)
def renderApi(swagger, templatePath): if not isTemplatePathValid(templatePath): return with open(templatePath) as f: template = f.read() ''' api context { 'package': 'xxx', 'modelPackage': 'xxx', 'imports': [{'import': 'xxx'}, ...] 'classname': 'xxx', // seems that each class is created according to the 'tags''s last item 'operations': [ { 'summary': 'xxx', 'apiDescription': 'xxx', 'methodName': 'xxx', 'httpMethod': 'xxx', 'path': 'xxx', 'responseType': 'xxx', 'hasForm': true/false, 'parameters':[ { 'paramIn': 'xxx', 'inKey': 'xxx', 'paramName': 'xxx', 'paramDescription': 'xxx', 'paramType': 'xxx', 'isEnum': 'xxx', 'enumValues': [...], 'hasMore': true/false } ] } ] } ''' # get tags list first, the list item claims the api class name contexts = {} tags = set() if swagger.tags: for tag in swagger.tags: tags.add(tag.get('name')) for path in swagger.paths: for operation in path.operations: if operation.tags: tags.add(operation.tags[-1]) else: # this operation has no tags, generate one by the path. add the tag to the operation's 'tags' tag = getTagByPath(path.path) tags.add(tag) operation.tags = [tag] # now we have all tags. create blank render context for each one for tag in tags: context = {} context['package'] = apiPackage context['modelPackage'] = modelPackage context['classname'] = toApiClassName(tag) context['operations'] = [] contexts[tag] = context # fill operations for path in swagger.paths: for operation in path.operations: # tags has been filled above, won't be null tag = operation.tags[-1] context = contexts[tag] optContext = {} optContext['summary'] = operation.summary optContext['apiDescription'] = operation.description pathVar = path.path pathVar = re.sub(r'^/*(.*)', r'\1', pathVar) pathVar = re.sub(r'([^/]*)/*$', r'\1', pathVar) optContext['path'] = pathVar optContext['httpMethod'] = toFieldName(operation.method, True) optContext['methodName'] = toApiMethodName(operation.method, path.path) responseType = None for responseItem in operation.responses: if responseItem.code.startswith('2'): # try to parse response type if not responseItem.schema: responseType = 'Void' else: isArray = responseItem.schema.get('type') if isArray: items = responseItem.schema.get('items') if items: itemRef = items.get('$ref') if itemRef: responseType = toDataType('array') % refToClassName(itemRef, True) else: ref = responseItem.schema.get('$ref') responseType = refToClassName(ref, True) optContext['responseType'] = responseType parameters = [] for parameter in operation.parameters: paramSrc = None if parameter.ref: # parse the reference type, name = util.parseSwaggerRef(parameter.ref) for p in swagger.parameters: if p.key == name: paramSrc = p else: paramSrc = parameter pContext = {} # if paramter 'in' is 'formData', 'paramIn' value in Retrofit is 'Field' if paramSrc.location == 'formData': pContext['paramIn'] = 'Field' optContext['hasForm'] = True else: pContext['paramIn'] = util.camelize(paramSrc.location) # in retrofit annotations, @Body and @QueryMap(impossible in this parser) don't need a value if str(paramSrc.location).lower() != 'body': pContext['inKey'] = paramSrc.name pContext['paramName'] = toFieldName(paramSrc.name) pContext['paramDescription'] = paramSrc.description pType = None # now simply consider the schema is a json object, not an array if paramSrc.schema: ref = paramSrc.schema.get("$ref") if ref: pType = refToClassName(ref, True) else: pType = toDataType(paramSrc.type) if paramSrc.type == 'array': if paramSrc.itemRef: pType = pType % refToClassName(paramSrc.itemRef, True) elif paramSrc.itemType: pType = pType % toDataType(paramSrc.itemType, True) if paramSrc.itemEnum: pContext['isEnum'] = 'true' pContext['enumValues'] = paramSrc.itemEnum pContext['paramType'] = pType pContext['hasMore'] = True parameters.append(pContext) if len(parameters) > 0: parameters[-1]['hasMore'] = False optContext['parameters'] = parameters context['operations'].append(optContext) # now we have contexts. render each one for key in contexts: context = contexts.get(key) result = pystache.render(template, context) savePath = apiDir + '/' + context['classname'] + '.java' saveTo(savePath, result)
def pkg(class_name): return self.java_class_visitor.package \ + (('.' + util.camelize(self.n2)) if not module else '') \ + '.' + class_name
def generate_visitor(self, stmt, module=False): def pkg(class_name): return self.java_class_visitor.package \ + (('.' + util.camelize(self.n2)) if not module else '') \ + '.' + class_name def if_none_then_null(val): return ('"' + val + '"') if val is not None else 'null' method_visit = JavaMethod(return_type='void', name='visit') method_visit.add_javadoc('Auto-generated module traverse algorithm') method_visit.add_parameter('io.netconfessor.NodeSet', 'nodes') method_visit.add_modifier('public') method_visit.add_dependency('io.netconfessor.Element') this_config = util.is_config(stmt) stmt_id = util.camelize(stmt.arg) stmt_class = util.normalize(stmt.arg) method_collect = None # module visitor collects into NodeSet, children into corresponding java object if module: method_collect = JavaMethod(return_type='io.netconfessor.NodeSet', name='collectConfig') method_collect.add_modifier('public') method_collect.add_line('NodeSet nodes = new NodeSet();') elif this_config: method_collect = JavaMethod(return_type=self.package + '.' + self.n, name='collectConfig') if stmt.keyword in {'list', 'leaf-list'}: method_collect.add_parameter(param_type=pkg(stmt_class), param_name=stmt_id) # method_collect.add_line('%s %s = getNext%s();' % (stmt_class, stmt_id, stmt_class)) method_collect.add_line('if (%s == null) {' % stmt_id) method_collect.add_line(' return null;') method_collect.add_line('}') else: method_collect.add_line('%s %s = new %s();' % (stmt_class, stmt_id, stmt_class)) method_collect.add_modifier('public') method_setup_all = JavaMethod(return_type='void', name='setup') method_setup_all.add_modifier('public') for s in util.search(stmt, context.yangelement_stmts): config = util.is_config(s) xpath = statements.mk_path_str(s, True) keyword = s.keyword id = util.camelize(s.arg) visitee_name = util.normalize(s.arg) visitee = util.escape_conflicts(pkg(visitee_name)) visitor_id = util.visitor_class(id) visitee_full = pkg(visitee_name) if keyword in {'container'}: method_name = 'on' + visitee_name next_visitor = util.visitor_class(visitee_name) visit_method = JavaMethod( return_type='void', # pkg(next_visitor), name=method_name) visit_method.add_parameter(visitee_full, keyword) visit_method.add_modifier('public') visit_method.add_modifier('abstract') self.java_class_visitor.add_method(visit_method) field_visitor = JavaValue() field_visitor.add_modifier('private') field_visitor.add_modifier(next_visitor) field_visitor.set_name(util.visitor_class(id)) self.java_class_visitor.add_field(field_visitor) if config: method_collect.add_line('if (%s != null) {' % visitor_id) method_collect.add_line(' %s %s = %s.collectConfig();' % (visitee, id, visitor_id)) method_collect.add_line(' if (%s != null) {' % id) if module: method_collect.add_line(' nodes.add(%s);' % id) else: method_collect.add_line(' %s.add%s(%s);' % (stmt_id, visitee_name, id)) method_collect.add_line(' }') method_collect.add_line('}') method_visit.add_line('') method_visit.add_line('final Element %s = nodes.getFirstChild("%s");' % (id, s.arg)) method_visit.add_line('if (%s != null) {' % id) method_visit.add_line(' %s((%s)%s);' % (method_name, visitee, id)) method_visit.add_line(' if (%s != null) {' % visitor_id) method_visit.add_line(' if (%s.hasChildren()) {' % id) method_visit.add_line(' %s.visit(%s.getChildren());' % (visitor_id, id)) method_visit.add_line(' }') method_visit.add_line(' }') method_visit.add_line('}') method_visit.add_dependency(pkg(next_visitor)) method_setup = JavaMethod(return_type=pkg(next_visitor), name='setup' + visitee_name) method_setup.add_modifier('public') method_setup.add_modifier('abstract') method_setup.add_parameter(param_type='io.netconfessor.YangData', param_name='data') desc_stmt = util.search_one(s, 'description') desc = if_none_then_null(desc_stmt.arg if desc_stmt is not None else None) method_setup_all.add_line('%s = setup%s(new YangData("%s", "%s", %s, %s, YangDataType.%s));' % (visitor_id, visitee_name, s.arg, xpath, util.yang_string_to_jstring(desc), 'true' if config else 'false', util.camelize(s.keyword))) method_setup_all.add_line('if (%s != null) {' % visitor_id) method_setup_all.add_line(' %s.setup();' % visitor_id) method_setup_all.add_line('}') method_setup_all.add_dependency('io.netconfessor.YangData') method_setup_all.add_dependency('io.netconfessor.YangDataType') self.java_class_visitor.add_field(method_setup) elif keyword in {'list'}: next_method_name = 'onNext' + visitee_name entry_visitor = util.visitor_class(visitee_name) visit_method = JavaMethod(return_type='void', # pkg(entry_visitor), name=next_method_name) visit_method.add_modifier('public') visit_method.add_modifier('abstract') visit_method.add_parameter(visitee_full, 'item') self.java_class_visitor.add_method(visit_method) start_method_name = 'onStart' + visitee + 'List' visit_method = JavaMethod(return_type='void', name=start_method_name) visit_method.add_modifier('protected') self.java_class_visitor.add_method(visit_method) stop_method_name = 'onStop' + visitee + 'List' visit_method = JavaMethod(return_type='void', name=stop_method_name) visit_method.add_modifier('protected') self.java_class_visitor.add_method(visit_method) if config: collect_get_next_name = 'getNext' + visitee_name method_collect.add_line('%s %s;' % (util.escape_conflicts(visitee, visitee_name), id)) method_collect.add_line('while((%s = %s()) != null) {' % (id, collect_get_next_name)) if module: method_collect.add_line(' nodes.add(%s);' % id) else: method_collect.add_line(' %s.removeNonKeysIfMarkedToDelete();' % id) method_collect.add_line(' %s.add%s(%s);' % (stmt_id, visitee_name, id)) method_collect.add_line('}') collect_get_next = JavaMethod(return_type=visitee_full, name=collect_get_next_name) collect_get_next.add_modifier('abstract') collect_get_next.add_modifier('protected') self.java_class_visitor.add_method(collect_get_next) method_visit.add_line('') method_visit.add_line('%s();' % start_method_name) method_visit.add_line('for (Element node : nodes.getChildren("%s")) {' % (s.arg)) method_visit.add_line(' %s((%s)node);' % (next_method_name, visitee)) method_visit.add_line(' if (%s != null) {' % visitor_id) method_visit.add_line(' if (node.hasChildren()) {') method_visit.add_line(' %s.visit(node.getChildren());' % visitor_id) method_visit.add_line(' }') method_visit.add_line(' }') method_visit.add_line('}') method_visit.add_line('%s();' % stop_method_name) method_setup = JavaMethod(return_type=pkg(entry_visitor), name='setup' + visitee_name) method_setup.add_modifier('public') method_setup.add_modifier('abstract') method_setup.add_parameter(param_type='io.netconfessor.YangData', param_name='data') self.java_class_visitor.add_field(method_setup) desc_stmt = util.search_one(s, 'description') desc = if_none_then_null(desc_stmt.arg if desc_stmt is not None else None) method_setup_all.add_line('%s = setup%s(new YangData("%s", "%s", %s, %s, YangDataType.%s));' % (visitor_id, visitee_name, s.arg, xpath, util.yang_string_to_jstring(desc), 'true' if config else 'false', util.camelize(s.keyword))) method_setup_all.add_line('if (%s != null) {' % visitor_id) method_setup_all.add_line(' %s.setup();' % visitor_id) method_setup_all.add_line('}') method_setup_all.add_dependency('io.netconfessor.YangData') method_setup_all.add_dependency('io.netconfessor.YangDataType') field_visitor = JavaValue() field_visitor.add_modifier('private') field_visitor.add_modifier(entry_visitor) field_visitor.set_name(util.visitor_class(id)) self.java_class_visitor.add_field(field_visitor) elif keyword in {'leaf'}: method_name = 'on' + visitee visit_method = JavaMethod(return_type='void', name=method_name) visit_method.add_modifier('public') visit_method.add_modifier('abstract') visit_method.add_parameter(visitee_full, keyword) self.java_class_visitor.add_method(visit_method) jnc, primitive = util.get_types(s, self.ctx) type_reference = util.escape_conflicts(visitee, visitee_name) base_type = util.get_base_type(s) is_enum = base_type.arg == 'enumeration' type_class = util.escape_conflicts(jnc, visitee_name) if config: get_method = JavaMethod(name='get' + visitee) get_method.set_return_type(visitee, visitee_name) get_method.add_modifier('public') get_method.add_modifier('abstract') self.java_class_visitor.add_method(get_method) method_collect.add_line('%s %s = get%s();' % (visitee_name, id, visitee_name)) method_collect.add_line('if (%s != null) {' % id) method_collect.add_line(' %s.add%s(%s);' % (stmt_id, visitee_name, id)) method_collect.add_line('}') method_visit.add_line('') method_visit.add_line('final Element %s = nodes.getFirstChild("%s");' % (id, s.arg)) method_visit.add_line('if (%s != null) {' % id) method_visit.add_line(' %s((%s)%s);' % (method_name, type_reference, id)) method_visit.add_line('}') method_setup = JavaMethod(return_type='void', name='setup' + visitee_name) method_setup.add_modifier('public') method_setup.add_modifier('abstract') yang_data_type = 'io.netconfessor.EnumYangData' if is_enum else 'io.netconfessor.LeafYangData' method_setup.add_parameter_generic(param_type=yang_data_type, generic_type=jnc, param_name='data', this_class_name=visitee_full) desc_stmt = util.search_one(s, 'description') desc = if_none_then_null(desc_stmt.arg if desc_stmt is not None else None) if is_enum: method_setup_all.add_line('setup%s(new EnumYangData<>(' '"%s", "%s", %s, %s, YangDataType.%s, "%s", s -> new %s(s), %s.enums()));' % (visitee_name, s.arg, xpath, util.yang_string_to_jstring(desc), 'true' if config else 'false', util.camelize(s.keyword), jnc, type_class, type_class)) else: method_setup_all.add_line('setup%s(new LeafYangData<>(' '"%s", "%s", %s, %s, YangDataType.%s, "%s", s -> new %s(s)));' % (visitee_name, s.arg, xpath, util.yang_string_to_jstring(desc), 'true' if config else 'false', util.camelize(s.keyword), jnc, type_class)) method_setup_all.add_dependency(jnc) method_setup_all.add_dependency(yang_data_type) method_setup_all.add_dependency('io.netconfessor.YangDataType') self.java_class_visitor.add_field(method_setup) if module: method_collect.add_javadoc('Retrieve all config values in registered visitors') method_collect.add_javadoc('Before send to device you need sync result with older nodeset (empty allowed)') method_collect.add_line('return nodes;') elif this_config: method_collect.add_javadoc('Retrieve all config values in registered visitors') method_collect.add_line('if (%s.hasChildren()) {' % stmt_id) method_collect.add_line(' return %s;' % stmt_id) method_collect.add_line('} else {') method_collect.add_line(' return null;') method_collect.add_line('}') self.java_class_visitor.add_method(method_setup_all) self.java_class_visitor.add_method(method_collect) self.java_class_visitor.add_method(method_visit)
def record(stmt, package): for ch in util.search(stmt, context.yangelement_stmts): if package not in context.class_hierarchy: context.class_hierarchy[package] = set([]) context.class_hierarchy[package].add(util.normalize(ch.arg)) record(ch, '.'.join([package, util.camelize(ch.arg)]))