def _generate_view(module, appname, types): """Output integration view""" write = writer.Writer('plantuml') var_name = _make_varmgr(module, appname, write) with write.uml(): for (appname, name, typespec) in types: var_name(name) link_sets = collections.defaultdict( lambda: collections.defaultdict(list)) fields = sorted(typespec.tuple.attr_defs.iteritems(), key=_attr_sort_key) for (fieldname, fieldtype) in fields: cardinality = u' ' while fieldtype.WhichOneof('type') == 'list': fieldtype = fieldtype.list.type cardinality = u'0..*' if fieldtype.WhichOneof('type') == 'set': fieldtype = fieldtype.set cardinality = u'0..*' if fieldtype.WhichOneof('type') == 'type_ref': ref = u'.'.join(fieldtype.type_ref.ref.path) # Hacky! if ref.startswith(u'Common Data.'): continue refs = [n for (_, n, _) in types if n.endswith(ref)] line_template = u'{} {{}} *-- "{}" {}'.format( var_name(name), cardinality, var_name(refs[0]) if refs else ref) link_sets[ref][line_template].append(fieldname) for (_, line_templates) in link_sets.iteritems(): if len(line_templates) > 1: for (line_template, fieldnames) in line_templates.iteritems(): for fieldname in fieldnames: write(line_template, '"' + fieldname + '"') else: for (line_template, fieldnames) in line_templates.iteritems(): for _ in fieldnames: write(line_template, '') return str(write)
def main(): argp = argparse.ArgumentParser(description='import xsd to sysl') argp.add_argument('--appname', help='output appname') argp.add_argument('--package', help='output package') argp.add_argument('input', help='xsd input file') argp.add_argument('output', help='sysl output file') args = argp.parse_args() root = ET.XML(open(args.input).read()) w = writer.Writer('sysl') w('{}{}:', args.appname or os.path.splitext(os.path.basename(args.input))[0], ' [package="{}"]'.format(args.package) if args.package else '') with w.indent(): toplevel = [(e.get('name'), list(e)[0]) for e in findall(root, './xs:element[@name]')] secondary = [(ct.get('name'), ct) for ct in findall(root, './xs:complexType[@name]')] for (i, (tname, t)) in enumerate(toplevel + secondary): w('\n!type {}{}:'[not i:], tname, (' [xml_order=["index"]]' if any( attr.get('name') == 'index' for attr in findall(t, './xs:attribute')) else '')) with w.indent(): for attr in findall(t, './xs:attribute'): (type_, _) = BASE_TYPE_MAP[attr.get('type')] w('{} <: {}{} [~xml_attribute]', attr.get('name'), type_, '' if attr.get('use') == 'required' else '?') for field in (findall(t, './xs:sequence/xs:element') + findall(t, './xs:all/xs:element')): w('{} <: {}', field.get('name'), syslForField(field)) open(args.output, 'w').write(str(w))
def interface(interfaces, context): (app, module, package, model_class, write_file, _, _) = context for interface in interfaces: w = writer.Writer('java') java.Package(w, package) with java.Class(w, interface, write_file, type_='interface', visibility='public', package=package): scope = scopes.Scope(module) for (epname, endpt) in (sorted(app.endpoints.iteritems(), key=lambda t: (t[1].rest_params.path, t[0]))): if endpt.attrs['interface'].s != interface: continue if not endpt.HasField('rest_params'): continue rp = endpt.rest_params rest_method = rp.Method.Name(rp.method) method_name = ( rest_method + rex.sub(r'{(\w+)}', lambda m: m.group(1).upper(), rex.sub(r'[-/]', '_', rp.path))) w( 'public Object {}({});', method_name, ', '.join('\v{} {}'.format(t, p) for (t, p) in codeForParams(rp.query_param, scope)))
def serializer(context): (app, module, package, model_class, write_file, _, _) = context facade = bool(context.wrapped_model) w = writer.Writer('java') java.Package(w, package) java.StandardImports(w) java.Import(w, 'java.io.IOException') w.head() java.Import(w, 'java.text.ParseException') w.head() java.Import(w, 'com.fasterxml.jackson.core.JsonGenerator') java.Import(w, 'com.fasterxml.jackson.databind.JsonSerializer') java.Import(w, 'com.fasterxml.jackson.databind.SerializerProvider') w.head() java.Import(w, 'org.joda.time.format.DateTimeFormatter') java.Import(w, 'org.joda.time.format.ISODateTimeFormat') if facade: model_name = syslx.fmt_app_name(context.wrapped_model.name) modelpkg = syslx.View(context.wrapped_model.attrs)['package'].s w.head() java.Import(w, modelpkg + '.*') w() with java.Class(w, model_class + 'JsonSerializer', write_file, package=package, extends='JsonSerializer<' + model_class + '>'): w() with java.Method(w, 'public', 'void', 'serialize', [(model_class, 'facade' if facade else 'model'), ('JsonGenerator', 'g'), ('SerializerProvider', 'provider')], throws=['IOException'], override=True): if facade: w('{} model = facade.getModel();', model_name) w(u'g.writeStartObject();') for (tname, t) in sorted(app.types.iteritems()): if t.WhichOneof('type') == 'relation': w(u'serialize{0}View(g, model.get{0}Table());', tname) w(u'g.writeEndObject();') for (tname, t) in sorted(app.types.iteritems()): if not t.WhichOneof('type') in ['relation', 'tuple']: continue w() with java.Method(w, 'public', 'void', 'serialize' + tname + 'View', [('JsonGenerator', 'g'), (tname + '.View', 'view')], throws=['IOException']): with java.If(w, 'view.isEmpty()'): w('return;') w('g.writeArrayFieldStart("{}");', tname) with java.For(w, '{} item : view', tname): w('g.writeStartObject();') for (fname, f) in datamodel.sorted_fields(t): jfname = java.name(fname) method = java.CamelCase(jfname) type_ = datamodel.typeref(f, module)[2] extra = '{}' which_type = type_.WhichOneof('type') if which_type == 'primitive': (jsontype, extra) = JSON_GEN_MAP[type_.primitive] if type_.primitive == type_.DECIMAL: for c in type_.constraint: if c.scale: access = ( '{0} == null ? null : item.{0}.setScale({1}, ' 'java.math.RoundingMode.HALF_UP)').format( jfname, c.scale) break else: access = jfname elif which_type == 'enum': jsontype = 'Number' access = jfname + '.getValue()' elif which_type == 'tuple': access = jfname else: raise RuntimeError( 'Unexpected field type for JSON export: ' + which_type) w(u'writeField(g, "{}", {});', jfname, extra.format('item.' + access)) w(u'g.writeEndObject();') w(u'g.writeEndArray();') for t in ['Boolean', 'String']: w() with java.Method(w, 'private', 'void', 'writeField'.format(t), [('JsonGenerator', 'g'), ('String', 'fieldname'), (t, 'value')], throws=['IOException']): with java.If(w, 'value != null'): w('g.write{}Field(fieldname, value);', t) w() with java.Method(w, 'private', 'void', 'writeField'.format(t), [('JsonGenerator', 'g'), ('String', 'fieldname'), ('Integer', 'value')], throws=['IOException']): with java.If(w, 'value != null'): w('g.writeNumberField(fieldname, value.intValue());') w() with java.Method(w, 'private', 'void', 'writeField'.format(t), [('JsonGenerator', 'g'), ('String', 'fieldname'), ('Double', 'value')], throws=['IOException']): with java.If(w, 'value != null'): w('g.writeNumberField(fieldname, value.doubleValue());') w() with java.Method(w, 'private', 'void', 'writeField'.format(t), [('JsonGenerator', 'g'), ('String', 'fieldname'), ('BigDecimal', 'value')], throws=['IOException']): with java.If(w, 'value != null'): w('g.writeNumberField(fieldname, value);') w() with java.Method(w, 'private', 'void', 'writeField'.format(t), [('JsonGenerator', 'g'), ('String', 'fieldname'), ('DateTime', 'value'), ('DateTimeFormatter', 'fmt')], throws=['IOException']): with java.If(w, 'value != null'): w('g.writeStringField(fieldname, fmt.print(value));') w() with java.Method(w, 'private', 'void', 'writeField'.format(t), [('JsonGenerator', 'g'), ('String', 'fieldname'), ('LocalDate', 'value'), ('DateTimeFormatter', 'fmt')], throws=['IOException']): with java.If(w, 'value != null'): w('g.writeStringField(fieldname, fmt.print(value));') w() with java.Method(w, 'private', 'void', 'writeField'.format(t), [('JsonGenerator', 'g'), ('String', 'fieldname'), ('UUID', 'value')], throws=['IOException']): with java.If(w, 'value != null'): w('g.writeStringField(fieldname, value.toString());') w('\nprivate final DateTimeFormatter iso8601Date = ' 'ISODateTimeFormat.date();') w('private final DateTimeFormatter iso8601DateTime = ' 'ISODateTimeFormat.dateTime();')
def deserializer(context): (app, module, package, model_class, write_file, _, _) = context facade = bool(context.wrapped_model) w = writer.Writer('java') java.Package(w, package) java.StandardImports(w) java.Import(w, 'java.io.IOException') w.head() java.Import(w, 'java.text.ParseException') w.head() java.Import(w, 'com.fasterxml.jackson.core.JsonParseException') java.Import(w, 'com.fasterxml.jackson.core.JsonParser') java.Import(w, 'com.fasterxml.jackson.core.JsonToken') java.Import(w, 'com.fasterxml.jackson.databind.JsonDeserializer') java.Import(w, 'com.fasterxml.jackson.databind.DeserializationContext') w.head() java.Import(w, 'org.joda.time.format.DateTimeFormatter') java.Import(w, 'org.joda.time.format.ISODateTimeFormat') if facade: model_name = syslx.fmt_app_name(context.wrapped_model.name) modelpkg = syslx.View(context.wrapped_model.attrs)['package'].s w.head() java.Import(w, modelpkg + '.*') else: model_name = model_class has_tables = any( t.HasField('relation') for (tname, t) in sorted(app.types.iteritems())) w() with java.Class(w, model_class + 'JsonDeserializer', write_file, package=package, extends=has_tables and 'JsonDeserializer<' + model_class + '>'): if has_tables: w() with java.Method(w, 'public', model_class, 'deserialize', [('JsonParser', 'p'), ('DeserializationContext', 'provider')], throws=['IOException', 'JsonParseException'], override=True): w('{0} model = new {0}();', model_name) w() w('eatToken(p, JsonToken.START_OBJECT);') with java.While(w, 'p.getCurrentToken() != JsonToken.END_OBJECT'): with java.Switch(w, 'eatName(p)'): for (tname, t) in sorted(app.types.iteritems()): if t.HasField('relation'): w(('case "{0}": deserialize{0}Table(p, ' 'model.get{0}Table()); break;'), tname) w('default: skipJson(p);') w('expectToken(p, JsonToken.END_OBJECT);') w() w('return model;') for (tname, t) in sorted(app.types.iteritems()): if not t.HasField('relation'): continue pkey = datamodel.primary_key_params(t, context.module) pkey_fields = {f for (_, f, _) in pkey} fkeys = { java.name(fname): type_info for (fname, _, type_info) in datamodel.foreign_keys(t, context.module)} private_setters = pkey_fields | set(fkeys.iterkeys()) w() with java.Method(w, 'private', 'void', 'deserialize' + tname + 'Table', [('JsonParser', 'p'), (tname + '.Table', 'table')], throws=['IOException', 'JsonParseException']): w('eatToken(p, JsonToken.START_ARRAY);') with java.While(w, 'p.getCurrentToken() != JsonToken.END_ARRAY'): w('eatToken(p, JsonToken.START_OBJECT);') w('{0} entity = {0}._PRIVATE_new(table.model());', tname) with java.While(w, 'p.getCurrentToken() != JsonToken.END_OBJECT'): with java.Switch(w, u'eatName(p)'): for (fname, f) in datamodel.sorted_fields(t): jfname = java.name(fname) (typename, _, type_) = datamodel.typeref(f, module) extra = '{}' which_type = type_.WhichOneof('type') if which_type == 'primitive': jsontype = JSON_PARSE_MAP[type_.primitive] if isinstance(jsontype, tuple): (jsontype, extra) = jsontype elif which_type == 'enum': jsontype = 'IntValue' extra = typename + '.from({})' else: raise RuntimeError( 'Unexpected field type for JSON export: ' + which_type) private = '_PRIVATE_' if jfname in private_setters else '' if type_.primitive in [ sysl_pb2.Type.DATE, sysl_pb2.Type.DATETIME]: with java.Case(w, '"{}"', jfname): w(('entity.{}set{}(' 'p.getCurrentToken() == JsonToken.VALUE_NULL' ' ? null : {}); break;'), private, java.CamelCase(jfname), extra.format('p.get{}()'.format(jsontype))) else: w(('case "{}": entity.{}set{}(p.getCurrentToken() == ' 'JsonToken.VALUE_NULL ? null : {}); break;'), jfname, private, java.CamelCase(jfname), extra.format('p.get{}()'.format(jsontype))) with java.Default(w): w('skipJson(p);') w('continue;') w('p.nextToken();') w('p.nextToken();') w() w('table.insert(entity);') w('p.nextToken();') with java.Method(w, '\nprivate', 'void', 'eatToken', [('JsonParser', 'p'), ('JsonToken', 'token')], throws=['IOException']): w(u'expectToken(p, token);') w(u'p.nextToken();') with java.Method(w, '\nprivate', 'void', 'expectToken', [('JsonParser', 'p'), ('JsonToken', 'token')]): with java.If(w, 'p.getCurrentToken() != token'): w(('System.err.printf("<<Unexpected token: %s (expecting %s)>>\\n", ' 'tokenName(p.getCurrentToken()), tokenName(token));')) w('throw new {}Exception();', model_name) with java.Method(w, '\nprivate', 'String', 'eatName', [('JsonParser', 'p')], throws=['IOException']): w('expectToken(p, JsonToken.FIELD_NAME);') w('String name = p.getCurrentName();') w('p.nextToken();') w('return name;') with java.Method(w, '\nprivate', 'String', 'tokenName', [('JsonToken', 'token')]): with java.If(w, 'token == null'): w('return "null";') with java.Switch(w, 'token'): for tok in ( 'END_ARRAY END_OBJECT FIELD_NAME NOT_AVAILABLE START_ARRAY ' 'START_OBJECT VALUE_EMBEDDED_OBJECT VALUE_FALSE VALUE_NULL ' 'VALUE_NUMBER_FLOAT VALUE_NUMBER_INT VALUE_STRING VALUE_TRUE' ).split(): w('case {0}: return "{0}";', tok); w('return "";') # TODO: refactor into base class # TODO: replace recursion with depth counter with java.Method(w, '\nprivate', 'void', 'skipJson', [('JsonParser', 'p')], throws=['IOException']): w('JsonToken tok = p.getCurrentToken();') w('p.nextToken();') with java.Switch(w, 'tok'): for tok in ( 'VALUE_FALSE VALUE_NULL VALUE_NUMBER_FLOAT VALUE_NUMBER_INT ' 'VALUE_STRING VALUE_TRUE').split(): w('case {}: break;', tok) with java.Case(w, 'START_ARRAY'): with java.While(w, 'p.getCurrentToken() != JsonToken.END_ARRAY'): w('skipJson(p);') w('p.nextToken();') w('break;') with java.Case(w, 'START_OBJECT'): with java.While(w, 'p.getCurrentToken() != JsonToken.END_OBJECT'): w('p.nextToken();') w('skipJson(p);') w('p.nextToken();') w('break;') # TODO: Is permissive dateTimeParser OK for date types? w('\nprivate final DateTimeFormatter iso8601DateTime = ' 'ISODateTimeFormat.dateTimeParser();') w()
def export_facade_class(context): model_name = syslx.fmt_app_name(context.wrapped_model.name) modelpkg = syslx.View(context.wrapped_model.attrs)['package'].s w = writer.Writer('java') java.Package(w, context.package) java.StandardImports(w) java.Import(w, modelpkg + '.' + model_name) w() with java.Class(w, context.appname, context.write_file, package=context.package): with java.Ctor(w, '\npublic', context.appname, [(model_name, 'model')]): w('this.model = model;') for (tname, _, _) in syslx.wrapped_facade_types(context): w('this.{}Facade = new {}Facade();', java.safe(tname[:1].lower() + tname[1:]), tname) with java.Method(w, '\npublic', model_name, 'getModel'): w('return model;') java.SeparatorComment(w) for (tname, ft, t) in syslx.wrapped_facade_types(context): if t.HasField('relation'): pkey = datamodel.primary_key_params(t, context.module) pkey_fields = {f for (_, f, _) in pkey} param_defs = [(typ, jfname) for (typ, fname, jfname) in pkey if 'autoinc' not in syslx.patterns( t.relation.attr_defs[fname].attrs)] params = ''.join(', ' + f for (_, f) in param_defs) param = ', '.join(f for (_, f) in param_defs) fkeys = { java.name(fname): type_info for (fname, _, type_info ) in datamodel.foreign_keys(t, context.module) } inner_type = ('HashMap<Key, {}>' if pkey else 'HashSet<{}>').format(tname) required = [] for fname in sorted(ft.relation.attr_defs.keys()): f = t.relation.attr_defs.get(fname) if ('required' in syslx.patterns(f.attrs) or 'required' in syslx.patterns( ft.relation.attr_defs.get(fname).attrs)): jfname = java.name(fname) method = java.CamelCase(jfname) (java_type, type_info, _) = datamodel.typeref(f, context.module) if java_type == 'Object': datamodel.typeref(f, context.module) required.append((fname, java_type)) with java.Method(w, '\npublic', tname + 'Facade', 'get' + tname): w('return {}Facade;', java.safe(tname[:1].lower() + tname[1:])) w() with java.Class(w, tname + 'Facade', context.write_file): with java.Method(w, 'public', '{}.{}.Table'.format(modelpkg, tname), 'table'): w('return model.get{}Table();', tname, param) w() if param_defs or required: with java.Method(w, 'public', 'Builder0', 'build'): w('return new Builder0();') keytypes = {f: kt for (kt, f) in param_defs} keys = sorted(keytypes) keyindices = {k: i for (i, k) in enumerate(keys)} if len(keys) > 3: # 4 perms yields 16 builders with 32 setters. logging.error('OUCH! Too many primary key fields') import pdb pdb.set_trace() for perm in range(2**len(keys)): bname = 'Builder' + str(perm) w() with java.Class(w, bname, context.write_file): done = [ k for (i, k) in enumerate(keys) if 2**i & perm ] remaining = [k for k in keys if k not in done] with java.Ctor(w, '', bname, [(keytypes[k], k) for k in done]): for k in done: w('this.{0} = {0};', k) if required and not remaining: w( 'this._pending = {};', hex(2**len(required) - 1).rstrip('L')) for fname in remaining: f = t.relation.attr_defs[fname] jfname = java.name(fname) method = java.CamelCase(jfname) (java_type, type_info, _) = datamodel.typeref(f, context.module) next_bname = 'Builder{}'.format( perm | 2**keyindices[fname]) w() if jfname in fkeys: fk_type = fkeys[jfname].parent_path fk_field = fkeys[jfname].field if f.type_ref.ref.path[-1:] == [fname]: method_suffix = fk_type else: method_suffix = method + 'From' with java.Method( w, 'public', next_bname, 'with' + method_suffix, [(modelpkg + '.' + fk_type, 'entity')]): w( '{} {} = entity == null ? null : entity.get{}();', java_type, jfname, java.CamelCase(fk_field)) w( 'return new {}({});', next_bname, ', '.join(k for k in keys if k == fname or k in done)) else: with java.Method( w, 'public', next_bname, 'with' + java.CamelCase(fname), [(keytypes[fname], fname)]): w( 'return new {}({});', next_bname, ', '.join(k for k in keys if k == fname or k in done)) if not remaining: for (i, (r, rtype)) in enumerate(required): method = java.CamelCase(r) w() # TODO: jfname set in a previous loop?? if jfname in fkeys: fk_type = fkeys[jfname].parent_path fk_field = fkeys[jfname].field if f.type_ref.ref.path[-1:] == [ fname ]: method = fk_type else: method += 'From' with java.Method( w, 'public', bname, 'with' + method, [(modelpkg + '.' + fk_type, java.mixedCase(fk_type))]): with java.If( w, '(_pending & {}) == 0', hex(2**i)): # TODO: More specific exception w('throw new RuntimeException();' ) w('this.{0} = {0};', java.mixedCase(fk_type)) w('_pending &= ~{};', hex(2**i)) w('return this;') else: with java.Method( w, 'public', bname, 'with' + method, [(rtype, r)]): with java.If( w, '(_pending & {}) == 0', hex(2**i)): # TODO: More specific exception w('throw new RuntimeException();' ) w('this.{0} = {0};', r) w('_pending &= ~{};', hex(2**i)) w('return this;') with java.Method(w, '\npublic', modelpkg + '.' + tname, 'insert'): if required: with java.If(w, '_pending != 0'): # TODO: More specific exception w('throw new RuntimeException();' ) w( u'{} result = table()._PRIVATE_insert({});', modelpkg + '.' + tname, param) for (r, rtype) in required: if jfname in fkeys: fk_field = fkeys[ jfname].field w('result.set{}({});', fk_type, java.mixedCase(fk_type)) else: w('result.set{}({});', java.CamelCase(r), r) w('return result;') else: w( u'return table()._PRIVATE_insert({});', param) if done: w() w('// primary key') for d in done: w('private final {} {};', keytypes[d], d) if required and not remaining: w() w('// required fields') for (r, rtype) in required: if jfname in fkeys: fk_type = fkeys[jfname].parent_path fk_field = fkeys[jfname].field w('private {} {};', modelpkg + '.' + fk_type, java.mixedCase(fk_type)) else: w('private {} {};', rtype, r) w() w('private int _pending;') else: with java.Method(w, 'public', modelpkg + '.' + tname, 'insert'): w('{} result = table()._PRIVATE_insert();', modelpkg + '.' + tname) w('return result;') java.SeparatorComment(w) for (tname, _, t) in syslx.wrapped_facade_types(context): if t.HasField('relation'): w('private final {}Facade {}Facade;', tname, java.safe(tname[:1].lower() + tname[1:])) w() w('private final {}.{} model;', modelpkg, model_name) w()
def _generate_view(module, args, integrations, highlights, app, apps, endpt): write = writer.Writer('plantuml') """Output integration view""" app_attrs = syslx.View(app.attrs) endpt_attrs = syslx.View(endpt.attrs) highlight_color = app_attrs['highlight_color'].s arrow_color = app_attrs['arrow_color'].s indirect_arrow_color = app_attrs['indirect_arrow_color'].s diagram_title = '' if (app_attrs['title'].s or args.title): fmtfn = diagutil.parse_fmt(app_attrs['title'].s or args.title) diagram_title = fmtfn(epname=endpt.name, eplongname=endpt.long_name) def generate_component_view(): name_map = {} def make_varmgr(): """Return a variable manager instance.""" appfmt = syslx.View(module.apps.get( args.project).attrs)['appfmt'].s appfmt = diagutil.parse_fmt(appfmt) def new_var(var, name): """Outputs a new definition when VarManager makes a new variable.""" app = module.apps[name] write( '[{}] as {}{}', appfmt(appname=name_map.get(name, name), **diagutil.attr_fmt_vars(app.attrs)).replace( '\n', r'\n'), var, ' <<highlight>>' if name in highlights else '') return diagutil.VarManager(new_var) with write.uml(): if diagram_title: write('title ' + diagram_title) write('hide stereotype') write('scale max 16384 height') write('skinparam linetype ortho') write('skinparam component {{') write(' BackgroundColor FloralWhite') write(' BorderColor Black') write(' ArrowColor Crimson') if highlight_color: write(' BackgroundColor<<highlight>> ' + highlight_color) if arrow_color: write(' ArrowColor ' + arrow_color) if indirect_arrow_color and indirect_arrow_color != 'none': write(' ArrowColor<<indirect>> ' + indirect_arrow_color) write('}}') var_name = make_varmgr() if args.clustered or endpt_attrs['view'].s == 'clustered': clusters = diagutil.group_by( apps, key=lambda app: app.partition(' :: ')[0]) clusters = [(cluster, members) for (cluster, g) in clusters for members in [list(g)] if len(members) > 1] name_map = { app: app.partition(' :: ')[-1] or app for (cluster, members) in clusters for app in members } for (cluster, cluster_apps) in clusters: write('package "{}" {{', cluster) for app in cluster_apps: var_name(app) # write(' {}', var_name(app)) write('}}') calls_drawn = set() if endpt_attrs['view'].s == 'system': for ((app_a, _), (app_b, _)) in integrations: direct = {app_a, app_b} & highlights app_a = app_a.partition(' :: ')[0] app_b = app_b.partition(' :: ')[0] if app_a != app_b and (app_a, app_b) not in calls_drawn: if direct or indirect_arrow_color != 'none': write('{} --> {}{}', var_name(app_a), var_name(app_b), '' if direct else ' <<indirect>>') calls_drawn.add((app_a, app_b)) else: for ((app_a, _), (app_b, _)) in integrations: if app_a != app_b and (app_a, app_b) not in calls_drawn: direct = {app_a, app_b} & highlights if direct or indirect_arrow_color != 'none': write('{} --> {}{}', var_name(app_a), var_name(app_b), '' if direct else ' <<indirect>>') calls_drawn.add((app_a, app_b)) for appname in apps: for mixin in module.apps[appname].mixin2: mixin_name = syslx.fmt_app_name(mixin.name) mixin_app = module.apps[mixin_name] write('{} <|.. {}', var_name(mixin_name), var_name(appname)) #TODO Some serious refactoring def generate_state_view(): def make_varmgr(istoplevel=False): """Return a variable manager instance.""" appfmt = syslx.View(module.apps.get( args.project).attrs)['appfmt'].s appfmt = diagutil.parse_fmt(appfmt) def new_var(var, name): """Outputs a new definition when VarManager makes a new variable.""" #TODO dodgy, should be using context (look at syslseqs) if istoplevel: template = 'state "{}" as X{}{} {{' else: template = ' state "{}" as {}{}' (_, _, name) = name.partition(' : ') app = module.apps[name] write( template, appfmt(appname=name, **diagutil.attr_fmt_vars(app.attrs)).replace( '\n', r'\n'), var, ' <<highlight>>' if name in highlights else '') return diagutil.VarManager(new_var) def yield_call_statements(statements): for (_, stmt) in enumerate(statements): field = stmt.WhichOneof('stmt') if field == 'call': yield stmt elif field == 'alt': for (_, choice) in enumerate(stmt.alt.choice): for next_stmt in yield_call_statements(choice.stmt): yield next_stmt elif field in {'cond', 'loop', 'loop_n', 'foreach', 'group'}: for next_stmt in yield_call_statements( getattr(stmt, field).stmt): yield next_stmt with write.uml(): if diagram_title: write('title ' + diagram_title) write('left to right direction') write('scale max 16384 height') write('skinparam nodesep 10') #TODO[kirkpatg]: this should probably scale up & down based on nodes & connections write('skinparam ranksep 300') #write('skinparam linetype polyline') write('hide empty description') write('skinparam state {{') write(' BackgroundColor FloralWhite') write(' BorderColor Black') write(' ArrowColor Crimson') if highlight_color: write(' BackgroundColor<<highlight>> ' + highlight_color) if arrow_color: write(' ArrowColor ' + arrow_color) if indirect_arrow_color and indirect_arrow_color != 'none': write(' ArrowColor<<indirect>> ' + indirect_arrow_color) write(' ArrowColor<<internal>> ' + indirect_arrow_color) write('}}') var_name = make_varmgr() tl_var_name = make_varmgr(True) clusters = {} # group end points and build the declarations for (app_a, ep_a), (app_b, ep_b) in integrations: if app_a not in clusters: clusters[app_a] = set() if app_b not in clusters: clusters[app_b] = set() # create clients in the calling app clusters[app_a].add(ep_a) if app_a != app_b and not module.apps[app_a].endpoints[ ep_a].is_pubsub: clusters[app_a].add(ep_b + " client") clusters[app_b].add(ep_b) for cluster in clusters: tl_var_name(cluster) for member in clusters[cluster]: var_name(cluster + ' : ' + member) write('}}') processed = [] for ((app_a, ep_a), (app_b, ep_b)) in integrations: direct = {app_a, app_b} & highlights # build the label label = '' needs_int = app_a != app_b # if 'App1 Event' in ep_a: import pdb; pdb.set_trace() # import pdb; pdb.set_trace() for stmt in yield_call_statements( module.apps[app_a].endpoints[ep_a].stmt): app_b_name = ' :: '.join(part for part in stmt.call.target.part) if app_b == app_b_name and ep_b == stmt.call.endpoint: fmt_vars = diagutil.attr_fmt_vars(stmt.attrs) ptrns = syslx.patterns( module.apps[app_b].endpoints[ep_b].attrs) label = diagutil.parse_fmt(app.attrs["epfmt"].s)( needs_int=needs_int, patterns=', '.join(sorted(ptrns)), **fmt_vars) break flow = ".".join([app_a, ep_b, app_b, ep_b]) is_pubsub = module.apps[app_a].endpoints[ep_a].is_pubsub ep_b_client = ep_b + " client" if app_a != app_b: if is_pubsub: write('{} -{}> {}{}', var_name(app_a + ' : ' + ep_a), '[#black]', var_name(app_b + ' : ' + ep_b), ' : ' + label if label else '') else: write( '{} -{}> {}', var_name(app_a + ' : ' + ep_a), '[#' + indirect_arrow_color + ']-' if indirect_arrow_color else '[#silver]-', var_name(app_a + ' : ' + ep_b_client)) if flow not in processed: write('{} -{}> {}{}', var_name(app_a + ' : ' + ep_b_client), '[#black]', var_name(app_b + ' : ' + ep_b), ' : ' + label if label else '') processed.append(flow) else: write( '{} -{}> {}{}', var_name(app_a + ' : ' + ep_a), '[#' + indirect_arrow_color + ']-' if indirect_arrow_color else '[#silver]-', var_name(app_b + ' : ' + ep_b), ' : ' + label if label else '') if (args.epa) or endpt_attrs['view'].s == 'epa': generate_state_view() else: generate_component_view() return str(write)
def serializer(context): (app, module, package, model_class, write_file, _, _) = context facade = bool(context.wrapped_model) w = writer.Writer('java') java.Package(w, package) java.StandardImports(w) java.Import(w, 'java.text.ParseException') w.head() java.Import(w, 'javax.xml.stream.XMLStreamException') java.Import(w, 'javax.xml.stream.XMLStreamWriter') w.head() java.Import(w, 'org.joda.time.format.DateTimeFormatter') java.Import(w, 'org.joda.time.format.ISODateTimeFormat') if facade: model_name = syslx.fmt_app_name(context.wrapped_model.name) modelpkg = syslx.View(context.wrapped_model.attrs)['package'].s w.head() java.Import(w, modelpkg + '.*') else: modelpkg = package with java.Class(w, '\n{}XmlSerializer'.format(model_class), write_file, package=package): with java.Method(w, '\npublic', 'void', 'serialize', [(model_class, 'facade' if facade else 'model'), ('XMLStreamWriter', 'xsw')], throws=['XMLStreamException']): if facade: w('{} model = facade.getModel();', model_name) w('xsw.writeStartElement("{}");', model_class) for (tname, ft, t) in syslx.sorted_types(context): if t.WhichOneof('type') == 'relation': w('serialize(model.get{0}Table(), xsw, "{0}");', tname) w('xsw.writeEndElement();') for (tname, ft, t) in syslx.sorted_types(context): java.SeparatorComment(w) if t.WhichOneof('type') in ['relation', 'tuple']: with java.Method(w, '\npublic', 'void', 'serialize', [(modelpkg + '.' + tname + '.View', 'view'), ('XMLStreamWriter', 'xsw'), ('String', 'tag')], throws=['XMLStreamException']): with java.If(w, 'view == null || view.isEmpty()'): w('return;') if t.WhichOneof('type') == 'relation': w('xsw.writeStartElement("{}List");', tname) order = [ o.s for o in syslx.View(t.attrs)['xml_order'].a.elt ] if order: order_logic = [] for o in order: order_logic.append( ' i = io.sysl.ExprHelper.doCompare' '(a.get{0}(), b.get{0}());\n' ' if (i != 0) return i;\n'.format( java.CamelCase(o))) order_by = ( '.orderBy(\n' ' new java.util.Comparator<{0}> () {{\n' ' @Override\n' ' public int compare({0} a, {0} b) {{\n' ' int i;\n' '{1}' ' return 0;\n' ' }}\n' ' }})\n').format(tname, ''.join(order_logic)) else: order_by = '' with java.For(w, '{} item : view{}', modelpkg + '.' + tname, order_by): w('serialize(item, xsw, tag);', tname) if t.WhichOneof('type') == 'relation': w('xsw.writeEndElement();') with java.Method(w, '\npublic', 'void', 'serialize', [(modelpkg + '.' + tname, 'entity'), ('XMLStreamWriter', 'xsw')], throws=['XMLStreamException']): w('serialize(entity, xsw, "{}");', tname) with java.Method(w, '\npublic', 'void', 'serialize', [(modelpkg + '.' + tname, 'entity'), ('XMLStreamWriter', 'xsw'), ('String', 'tag')], throws=['XMLStreamException']): with java.If(w, 'entity == null'): w('return;') w('xsw.writeStartElement(tag);', tname) for wantAttrs in [True, False]: for (fname, f) in datamodel.sorted_fields(t): jfname = java.name(fname) method = java.CamelCase(jfname) tref = datamodel.typeref(f, module) type_ = tref[2] if not type_: continue extra = '' which_type = type_.WhichOneof('type') if which_type == 'primitive': extra = XML_GEN_MAP[type_.primitive] if type_.primitive == type_.DECIMAL: for c in type_.constraint: if c.scale: access = 'round(entity.get{}(), {})'.format( method, c.scale) break else: access = 'entity.get{}()'.format(method) elif which_type == 'enum': access = 'entity.get{}().getValue()'.format( method) elif which_type == 'tuple': access = 'entity.get{}()'.format(method) else: raise RuntimeError( 'Unexpected field type for XML export: ' + which_type) if wantAttrs == ('xml_attribute' in syslx.patterns(f.attrs)): if wantAttrs: w('serializeAttr("{}", {}{}, xsw);', jfname, access, extra) else: if jfname == 'index': import pdb pdb.set_trace() w('serializeField("{}", {}{}, xsw);', jfname, access, extra) w('xsw.writeEndElement();') with java.Method(w, '\npublic', 'void', 'serializeField', [('String', 'fieldname'), (modelpkg + '.' + tname + '.View', 'view'), ('XMLStreamWriter', 'xsw')], throws=['XMLStreamException']): with java.If(w, 'view != null && !view.isEmpty()'): w('serialize(view, xsw, fieldname);') with java.Method(w, '\npublic', 'void', 'serializeField', [('String', 'fieldname'), (modelpkg + '.' + tname, 'entity'), ('XMLStreamWriter', 'xsw')], throws=['XMLStreamException']): with java.If(w, 'entity != null'): w('serialize(entity, xsw, fieldname);') def serialize(t, access, extra_args=None): with java.Method( w, '\nprivate', 'void', 'serialize', ([(t, 'value')] + (extra_args or []) + [('XMLStreamWriter', 'xsw')]), throws=['XMLStreamException']): w('xsw.writeCharacters({});', access) serialize('String', 'value') serialize('Boolean', 'value.toString()') serialize('Integer', 'value.toString()') serialize('Double', 'value.toString()') serialize('BigDecimal', 'value.toString()') serialize('UUID', 'value.toString()') serialize('DateTime', 'fmt.print(value)', [('DateTimeFormatter', 'fmt')]) serialize('LocalDate', 'iso8601Date.print(value)') def serializeField(t, access, extra_args=None): with java.Method( w, '\nprivate', 'void', 'serializeField', ([('String', 'fieldname'), (t, 'value')] + (extra_args or []) + [('XMLStreamWriter', 'xsw')]), throws=['XMLStreamException']): with java.If(w, 'value != null'): w('xsw.writeStartElement(fieldname);') w('serialize(value{}, xsw);', ''.join(', ' + arg for (_, arg) in extra_args or [])) w('xsw.writeEndElement();') with java.Method( w, '\nprivate', 'void', 'serializeAttr', ([('String', 'fieldname'), (t, 'value')] + (extra_args or []) + [('XMLStreamWriter', 'xsw')]), throws=['XMLStreamException']): with java.If(w, 'value != null'): w('xsw.writeAttribute(fieldname, {});', access) serializeField('String', 'value') serializeField('Boolean', 'value.toString()') serializeField('Integer', 'value.toString()') serializeField('Double', 'value.toString()') serializeField('BigDecimal', 'value.toString()') serializeField('UUID', 'value.toString()') serializeField('DateTime', 'fmt.print(value)', [('DateTimeFormatter', 'fmt')]) serializeField('LocalDate', 'iso8601Date.print(value)') with java.Method(w, '\nprivate final', 'BigDecimal', 'round', [('BigDecimal', 'd'), ('int', 'scale')]): w('return d == null ? d : ' 'd.setScale(scale, java.math.RoundingMode.HALF_UP);') w('\nprivate final DateTimeFormatter iso8601Date = ' 'ISODateTimeFormat.date();') w('private final DateTimeFormatter iso8601DateTime = ' 'ISODateTimeFormat.dateTime();')
def deserializer(context): (app, module, package, model_class, write_file, _, _) = context facade = bool(context.wrapped_model) w = writer.Writer('java') java.Package(w, package) java.StandardImports(w) java.Import(w, 'javax.xml.stream.XMLStreamConstants') java.Import(w, 'javax.xml.stream.XMLStreamException') java.Import(w, 'javax.xml.stream.XMLStreamReader') w.head() java.Import(w, 'java.text.ParseException') w.head() java.Import(w, 'org.joda.time.format.DateTimeFormatter') java.Import(w, 'org.joda.time.format.ISODateTimeFormat') if facade: model_name = syslx.fmt_app_name(context.wrapped_model.name) modelpkg = syslx.View(context.wrapped_model.attrs)['package'].s w.head() java.Import(w, modelpkg + '.*') else: model_name = model_class modelpkg = package with java.Class(w, '\n{}XmlDeserializer'.format(model_class), write_file, package=package): with java.Method( w, 'public', 'void', 'deserialize', [(model_class, 'facade' if facade else 'model'), ('XMLStreamReader', 'xsr')], throws=[model_name + 'Exception', 'XMLStreamException']): if facade: w('{} model = facade.getModel();', model_name) w('expect(XMLStreamConstants.START_ELEMENT, xsr.next());') with java.While(w, 'xsr.next() == XMLStreamConstants.START_ELEMENT'): with java.Switch(w, 'xsr.getLocalName()'): for (tname, ft, t) in syslx.sorted_types(context): if t.HasField('relation'): w( 'case "{0}List": deserialize(model.get{0}Table(), xsr); break;', tname) w( 'case "{0}": deserializeOne(model.get{0}Table(), xsr); break;', tname) w('default: skipElement(xsr);') w('expect(XMLStreamConstants.END_ELEMENT, xsr.getEventType());') for (tname, ft, t) in syslx.sorted_types(context): pkey = datamodel.primary_key_params(t, context.module) pkey_fields = {f for (_, f, _) in pkey} fkeys = { java.name(fname): type_info for (fname, _, type_info) in datamodel.foreign_keys(t, context.module) } private_setters = pkey_fields | set(fkeys.iterkeys()) if not t.HasField('relation'): continue with java.Method(w, '\nprivate', 'void', 'deserialize', [(modelpkg + '.' + tname + '.Table', 'table'), ('XMLStreamReader', 'xsr')], throws=['XMLStreamException']): with java.While( w, 'xsr.next() == XMLStreamConstants.START_ELEMENT'): w('deserializeOne(table, xsr);') w('expect(XMLStreamConstants.END_ELEMENT, xsr.getEventType());' ) with java.Method(w, '\nprivate', 'void', 'deserializeOne', [(modelpkg + '.' + tname + '.Table', 'table'), ('XMLStreamReader', 'xsr')], throws=['XMLStreamException']): w('{0} entity = {0}._PRIVATE_new(table.model());', modelpkg + '.' + tname) with java.While( w, 'xsr.next() == XMLStreamConstants.START_ELEMENT'): with java.Switch(w, 'xsr.getLocalName()'): for (fname, f) in datamodel.sorted_fields(t): jfname = java.name(fname) (typename, _, type_) = datamodel.typeref(f, module) extra = '{}' which_type = type_.WhichOneof('type') if which_type == 'primitive': xmltype = XML_PARSE_MAP[type_.primitive] if isinstance(xmltype, tuple): (xmltype, extra) = xmltype elif which_type == 'enum': xmltype = 'IntValue' extra = typename + '.from({})' else: raise RuntimeError( 'Unexpected field type for XML export: ' + which_type) private = '_PRIVATE_' if jfname in private_setters else '' if type_.primitive in [ sysl_pb2.Type.DATE, sysl_pb2.Type.DATETIME ]: w( 'case "{}": entity.{}set{}(read{}(xsr, {})); break;', jfname, private, java.CamelCase(jfname), typename, extra) else: w( 'case "{}": entity.{}set{}(read{}(xsr)); break;', jfname, private, java.CamelCase(jfname), typename) w('default: skipField(xsr);') w('table.insert(entity);') w('expect(XMLStreamConstants.END_ELEMENT, xsr.getEventType());' ) with java.Method(w, '\nprivate', 'void', 'expect', [('int', 'expected'), ('int', 'got')]): with java.If(w, 'got != expected'): w('System.err.printf(\v' '"<<Unexpected token: %s (expecting %s)>>\\n", \v' 'tokenName(got), tokenName(expected));') w('throw new {}Exception();', model_name) with java.Method(w, '\nprivate', 'String', 'tokenName', [('int', 'token')]): with java.Switch(w, 'token'): for tok in ( 'ATTRIBUTE CDATA CHARACTERS COMMENT DTD END_DOCUMENT ' 'END_ELEMENT ENTITY_DECLARATION ENTITY_REFERENCE NAMESPACE ' 'NOTATION_DECLARATION PROCESSING_INSTRUCTION SPACE START_DOCUMENT ' 'START_ELEMENT'.split()): w('case XMLStreamConstants.{0}: return "{0}";', tok) w('return new Integer(token).toString();') def read(t, access, extra_args=None): with java.Method(w, '\nprivate', t, 'read' + t, [('XMLStreamReader', 'xsr')], throws=['XMLStreamException']): with java.If(w, '!getCharacters(xsr)'): w('return null;') w('{} result = {};', t, access) w('expect(XMLStreamConstants.END_ELEMENT, xsr.next());') w('return result;') read('String', 'xsr.getText()') read('Boolean', 'Boolean.parseBoolean(xsr.getText())') read('Integer', 'Integer.parseInt(xsr.getText())') read('Double', 'Double.parseDouble(xsr.getText())') read('BigDecimal', 'new BigDecimal(xsr.getText())') read('UUID', 'UUID.fromString(xsr.getText())') with java.Method(w, '\nprivate', 'DateTime', 'readDateTime', [('XMLStreamReader', 'xsr'), ('DateTimeFormatter', 'fmt')], throws=['XMLStreamException']): with java.If(w, '!getCharacters(xsr)'): w('return null;') w('DateTime result = fmt.parseDateTime(xsr.getText());') w('expect(XMLStreamConstants.END_ELEMENT, xsr.next());') w('return result;') with java.Method(w, '\nprivate', 'LocalDate', 'readLocalDate', [('XMLStreamReader', 'xsr'), ('DateTimeFormatter', 'fmt')], throws=['XMLStreamException']): with java.If(w, '!getCharacters(xsr)'): w('return null;') w('LocalDate result = fmt.parseLocalDate(xsr.getText());') w('expect(XMLStreamConstants.END_ELEMENT, xsr.next());') w('return result;') with java.Method(w, '\nprivate', 'void', 'skipField', [('XMLStreamReader', 'xsr')], throws=['XMLStreamException']): with java.If(w, 'getCharacters(xsr)'): w('expect(XMLStreamConstants.END_ELEMENT, xsr.next());') with java.Method(w, '\nprivate', 'boolean', 'getCharacters', [('XMLStreamReader', 'xsr')], throws=['XMLStreamException']): w('int tok = xsr.next();') with java.If(w, 'tok == XMLStreamConstants.END_ELEMENT'): w('return false;') w('expect(XMLStreamConstants.CHARACTERS, tok);') w('return true;') with java.Method(w, '\nprivate', 'void', 'skipElement', [('XMLStreamReader', 'xsr')], throws=['XMLStreamException']): with java.While(w, 'xsr.next() != XMLStreamConstants.END_ELEMENT'): with java.If( w, 'xsr.getEventType() == XMLStreamConstants.START_ELEMENT' ): w('skipElement(xsr);') # TODO: Is permissive dateTimeParser OK for date types? w('\nprivate final DateTimeFormatter iso8601DateTime = ' 'ISODateTimeFormat.dateTimeParser();') w()
def export(mode, module, appname, outdir, expected_package, entities, serializers): app = module.apps.get(appname) assert app, appname package = syslx.View(app.attrs)['package'].s if mode != 'xsd': assert package == expected_package, (package, expected_package) model_class = '_'.join(app.name.part).replace(' ', '') write_file = src.util.file.FileWriter(outdir, package, entities) inouts = [] for s in serializers: assert '_' in s, s (fmt, dirn) = s.split('_') fmts = ['json', 'xml'] if fmt == '*' else [fmt] dirns = ['in', 'out'] if dirn == '*' else [dirn] for fmt in fmts: for dirn in dirns: inouts.append(fmt + "_" + dirn) serializers = set(inouts) bogus_serializers = serializers - { 'json_in', 'json_out', 'xml_in', 'xml_out' } assert not bogus_serializers, bogus_serializers if app.HasField('wrapped'): model_name = syslx.fmt_app_name(app.wrapped.name) assert model_name in module.apps, ('missing app: ' + repr(model_name), module.apps.keys(), app.wrapped.endpoints.keys()) wrapped_model = module.apps[model_name] else: wrapped_model = None context = Context(app, module, package, model_class, write_file, appname, wrapped_model) def serializer_entities(): return (({appname + 'JsonDeserializer'} if 'json_in' in serializers else set()) | ({appname + 'JsonSerializer'} if 'json_out' in serializers else set()) | ({appname + 'XmlDeserializer'} if 'xml_in' in serializers else set()) | ({appname + 'XmlSerializer'} if 'xml_out' in serializers else set())) def export_serializers(): if 'json_in' in serializers: json_export.deserializer(context) if 'json_out' in serializers: json_export.serializer(context) if 'xml_in' in serializers: xml_export.deserializer(context) if 'xml_out' in serializers: xml_export.serializer(context) if mode == 'model': entities |= {appname, appname + 'Exception'} | serializer_entities() # Build a foreign key reverse map to enable efficeint navigation # in the generated classes fk_rmap = datamodel.build_fk_reverse_map(app, module) # For each of the "types" in the Application message from the # protocol buffer represenation of the sysl generate an # "Entity" class for (tname, t) in sorted(app.types.iteritems()): if not re.match(r'AnonType_\d+__$', tname): w = writer.Writer('java') java.Package(w, package) java.StandardImports(w) java_model.export_entity_class(w, tname, t, fk_rmap[tname], context) java_model.export_model_class(fk_rmap, context) java_model.export_exception_class(context) export_serializers() elif mode == 'facade': entities |= {appname} | serializer_entities() java_facade.export_facade_class(context) export_serializers() elif mode == 'xsd': xsd_export.xsd(context) elif mode == 'swagger': swagger_export.swagger_file(app, module, model_class, write_file) elif mode == 'spring-rest-service': interfaces = { endpt.attrs['interface'].s for endpt in app.endpoints.itervalues() } assert None not in interfaces, '\n' + '\n'.join( sorted([ endpt.name for endpt in app.endpoints.itervalues() for i in [endpt.attrs['interface'].s] if not i ], key=lambda name: reversed(name.split()))) entities |= {model_class + 'Controller'} | set(interfaces) src.exporters.api.spring_rest.service(interfaces, context) elif mode == 'view': entities |= {appname} w = writer.Writer('java') java.Package(w, package) java.StandardImports(w) w() java.Import(w, 'org.joda.time.DateTime') java.Import(w, 'org.joda.time.format.DateTimeFormat') java.Import(w, 'org.joda.time.format.DateTimeFormatter') w() java_model.export_view_class(w, context)
def xsd(context): w = writer.Writer('xml') w.increment = 2 xsd_separator = '<!-- ' + '=' * 55 + ' -->' def e(_name, **attrs): if _name.endswith('/'): w( u'<{}{}/>', _name[:-1], u''.join(u' {}="{}"'.format(k.replace('_', ':'), v) for (k, v) in attrs.iteritems())) else: @contextlib.contextmanager def f(): w( u'<{}{}>', _name, u''.join(u' {}="{}"'.format(k.replace('_', ':'), v) for (k, v) in attrs.iteritems())) with w.indent(): yield w(u'</{}>', _name) return f() def xs(_name, **attrs): return e('xs:' + _name, **attrs) def build_relational_xsd(): # top level element contains all entities for # relational schemas but will only contain the # root entity for hierarchical with xs('element', name=context.model_class): with xs('complexType'): with xs('sequence', minOccurs=1, maxOccurs=1): # each "relation" is a list of things for (tname, ft, t) in syslx.sorted_types(context): if t.HasField('relation'): xs('element/', name=tname + 'List', type=tname + 'List', minOccurs=0) # build keys and key refs for (tname, ft, t) in syslx.sorted_types(context): if t.HasField('relation'): pkey = datamodel.primary_key_params(t, context.module) pkey_fields = {f for (_, f, _) in pkey} has_content = False def xsd_key_header(msg): w('{}', '<!-- ' + msg.center(55) + ' -->') if pkey: if not has_content: has_content = True w() w(xsd_separator) xsd_key_header(tname + ' keys') with xs('key', name='key_' + tname): xs('selector/', xpath='./{0}List/{0}'.format(tname)) for f in sorted(pkey_fields): xs('field/', xpath=f) for (i, (fname, _, type_info)) in enumerate( sorted(datamodel.foreign_keys(t, context.module))): if not has_content: has_content = True w() w(xsd_separator) xsd_key_header(tname + ' keyrefs') elif pkey and i == 0: xsd_key_header('keyrefs') fk_type = type_info.parent_path fk_field = type_info.field with xs('keyref', name='keyref_{}_{}'.format(tname, fname), refer='key_' + fk_type): xs('selector/', xpath='./{0}List/{0}'.format(tname)) xs('field/', xpath=fname) if has_content: w(xsd_separator) w() w() # construct the entities for (tname, ft, t) in syslx.sorted_types(context): if t.HasField('relation'): with xs('complexType', name=tname + 'List'): with xs('sequence', maxOccurs='unbounded'): with xs('element', name=tname): with xs('complexType'): with xs('all'): for (fname, f) in sorted( t.relation.attr_defs.iteritems()): jfname = java.name(fname) method = java.CamelCase(jfname) type_ = datamodel.typeref( f, context.module)[2] which_type = type_.WhichOneof('type') if which_type == 'primitive': xsdtype = XSD_TYPE_MAP[ type_.primitive] elif which_type == 'enum': xsdtype = 'xs:int' else: raise RuntimeError( 'Unexpected field type for XSD ' 'export: ' + which_type) xs('element/', name=jfname, type=xsdtype, minOccurs=0) def build_hierarchical_xsd(): def build_element(attr_fname, attr_f, is_set, is_attr): jfname = java.name(attr_fname) method = java.CamelCase(jfname) type_ = datamodel.typeref(attr_f, context.module)[2] which_type = type_.WhichOneof('type') if which_type == 'primitive': xsdtype = XSD_TYPE_MAP[type_.primitive] elif which_type == 'enum': xsdtype = 'xs:int' elif which_type == 'tuple': offset = -1 if is_set: offset = -2 xsdtype = datamodel.typeref( f, context.module)[0].split('.')[offset] else: raise RuntimeError('Unexpected field type for XSD ' 'export: ' + which_type) if is_attr: xs('attribute/', name=jfname, type=xsdtype, use='optional') else: xs('element/', name=jfname, type=xsdtype, minOccurs=0) # Top level element with xs('element', name=context.model_class): with xs('complexType'): with xs('sequence', minOccurs=1, maxOccurs=1): for (tname, ft, t) in syslx.sorted_types(context): if 'xml_root' in syslx.patterns(t.attrs): xs('element/', name=tname, type=tname, minOccurs=0) break w(xsd_separator) for (tname, ft, t) in syslx.sorted_types(context): with xs('complexType', name=tname): with xs('all'): for (fname, f) in sorted(t.tuple.attr_defs.iteritems()): if not 'xml_attribute' in syslx.patterns(f.attrs): if f.HasField('set'): with xs('element', name=fname + 'List'): with xs('complexType'): with xs('sequence', maxOccurs='unbounded'): build_element( fname, f, True, False) else: build_element(fname, f, False, False) #attributes second for (fname, f) in sorted(t.tuple.attr_defs.iteritems()): if 'xml_attribute' in syslx.patterns(f.attrs): build_element(fname, f, True, True) def build_xsd(): for (_, _, t) in syslx.sorted_types(context): if t.HasField('relation'): build_relational_xsd() return build_hierarchical_xsd() with e('xs:schema', xmlns_xs='http://www.w3.org/2001/XMLSchema', attributeFormDefault='unqualified', elementFormDefault='qualified', version='1.0'): build_xsd() context.write_file(w, context.model_class + '.xsd')
def main(): [swagger_path, appname, package, outfile] = sys.argv[1:] swag = yaml.load(open(swagger_path)) w = writer.Writer('sysl') if 'info' in swag: def info_attrs(info, prefix=''): for (name, value) in sorted(info.iteritems()): if isinstance(value, dict): info_attrs(value, prefix + name + '.') else: w('@{}{} = {}', prefix, name, json.dumps(value)) title = swag['info'].pop('title', '') info_attrs(swag['info']) else: title = '' if 'host' in swag: w('@host = {}', json.dumps(swag['host'])) w(u'{}{} [package={}]:', appname, title and ' ' + json.dumps(title), json.dumps(package)) with w.indent(): w(u'| {}', swag['info'].get('description', 'No description.')) for (path, api) in sorted(swag['paths'].iteritems()): # {foo-bar} to {fooBar} w(u'\n{}:', re.sub(r'({[^/]*?})', javaParam, path)) with w.indent(): if 'parameters' in api: del api['parameters'] for (i, (method, body)) in enumerate( sorted(api.iteritems(), key=lambda t: METHOD_ORDER[t[0]])): qparams = dict() if body.has_key( 'parameters') and 'in' in body['parameters']: qparams = [ p for p in body['parameters'] if p['in'] == 'query' ] w( u'{}{}{}:', method.upper(), ' ?' if qparams else '', '&'.join( ('{}={}{}'.format(p['name'], SWAGGER_TYPE_MAP[ p['type']], '' if p['required'] else '?') if p['type'] != 'string' else '{name}=string'.format( **p)) for p in qparams)) with w.indent(): for line in textwrap.wrap( body.get('description', 'No description.').strip(), 64): w(u'| {}', line) responses = body['responses'] errors = ','.join( sorted(str(e) for e in responses if e >= 400)) if 200 in responses: r200 = responses[200] if 'schema' in r200: ok = r200['schema'] if ok.get('type') == 'array': items = ok['items'] if '$ref' in items: itemtype = items['$ref'][ len('#/definitions/'):] ret = ': <: set of ' + itemtype else: ret = ': <: ...' elif ok.has_key('$ref'): ret = ': <: ' + ok['$ref'][ len('#/definitions/'):] else: ret = ' (' + r200.get('description') + ')' else: ret = ' (' + r200.get('description') + ')' w(u'return 200{} or {{{}}}', ret, errors) elif 201 in responses: r201 = responses[201] if 'headers' in r201: ok = r201['headers'] w(u'return 201 ({}) or {{{}}}', ok['Location']['description'], errors) else: w(u'return 201 ({})', r201['description']) if i < len(api) - 1: w() w() w('#' + '-' * 75) w('# definitions') for (tname, tspec) in sorted(swag['definitions'].iteritems()): w() w('!type {}:', tname) with w.indent(): tspec_items = tspec.get('properties') if tspec_items: for (fname, fspec) in sorted(tspec_items.iteritems()): (ftype, fdescr) = parse_typespec(fspec) w( '{} <: {}{}', fname, ftype if ftype.startswith('set of ') or ftype.endswith('*') else ftype + '?', ' "' + fdescr + '"' if fdescr else '') # handle top-level arrays elif tspec.has_key('type') and tspec['type'] == 'array': (ftype, fdescr) = parse_typespec(tspec) w( '{} <: {}{}', fname, ftype if ftype.startswith('set of ') or ftype.endswith('*') else ftype + '?', ' "' + fdescr + '"' if fdescr else '') else: assert True, tspec open(outfile, 'w').write(str(w))
def controller(interfaces, context): (app, module, package, model_class, write_file, _, _) = context w = writer.Writer('java') java.Package(w, package) java.Import(w, 'io.swagger.annotations.Api') java.Import(w, 'io.swagger.annotations.ApiOperation') java.Import(w, 'io.swagger.annotations.ApiParam') java.Import(w, 'io.swagger.annotations.ApiResponse') java.Import(w, 'io.swagger.annotations.ApiResponses') java.Import(w, 'lombok.extern.slf4j.Slf4j') java.Import(w, 'org.springframework.beans.factory.annotation.Autowired') java.Import(w, 'org.springframework.web.bind.annotation.PathVariable') java.Import(w, 'org.springframework.web.bind.annotation.RequestHeader') java.Import(w, 'org.springframework.web.bind.annotation.RequestMapping') java.Import(w, 'org.springframework.web.bind.annotation.RequestMethod') java.Import(w, 'org.springframework.web.bind.annotation.RequestParam') java.Import(w, 'org.springframework.web.bind.annotation.ResponseBody') java.Import(w, 'org.springframework.web.bind.annotation.RestController') w() w('@Api(value = {}, description = {}, position = {})', json.dumps(app.long_name), json.dumps(syslx.View(app.attrs)['description'].s), 1) w('@Slf4j') w('@RestController') w('@ResponseBody') w('@RequestMapping(value = {}, produces = {})', json.dumps('/'), json.dumps('application/json;version=1.0;charset=UTF-8;')) with java.Class(w, model_class + 'Controller', write_file, visibility='public', package=package): for (i, interface) in enumerate( sorted({ endpt.attrs['interface'].s for endpt in app.endpoints.itervalues() })): assert interface, '\n' + '\n'.join( sorted([ endpt.name.split()[1] + ' ' + endpt.name.split()[0] for endpt in app.endpoints.itervalues() for i in [endpt.attrs['interface'].s] if not i ])) w('\n@Autowired'[not i:]) w('private {} {};', interface, java.mixedCase(interface)) scope = scopes.Scope(module) for (epname, endpt) in (sorted(app.endpoints.iteritems(), key=lambda t: (t[1].rest_params.path, t[0]))): if not endpt.HasField('rest_params'): continue rp = endpt.rest_params rest_method = rp.Method.Name(rp.method) method_name = (rest_method + rex.sub(r'{(\w+)}', lambda m: m.group(1).upper(), rex.sub(r'[-/]', '_', rp.path))) def responses(stmts, result=None, cond=''): if result is None: result = collections.defaultdict(list) for stmt in stmts: which_stmt = stmt.WhichOneof('stmt') if which_stmt == 'cond': responses(stmt.cond.stmt, result, (cond and cond + ' & ') + stmt.cond.test) elif which_stmt == 'ret': m = rex.match( ur''' (?: (?: (\d+)· (\([^\)]+\))?· (\w+)?· (?: <:· (empty\s+)? (set\s+of\s+)? ([\w.]+|\.\.\.) )? ) | (?: one\s+of·{((?:\d+·,·)*\d+·)} ) )? $ ''', stmt.ret.payload) if m: [ status, descr, expr, empty, setof, type_, statuses ] = m.groups() for status in rex.split(ur'·,·', status or statuses): status = int(status) result[int(status)].append( cond or descr or STATUS_MAP.get(int(status)) or '???') else: print ` stmt.ret.payload ` import pdb pdb.set_trace() return result w() w('@RequestMapping(method = RequestMethod.{}, \vpath = {})', rest_method, json.dumps(rp.path)) w('@ApiOperation(value = {})', json.dumps(endpt.docstring)) w('@ApiResponses({{') with w.indent(): for (status, conds) in sorted(responses(endpt.stmt).iteritems()): w('@ApiResponse(code = {}, message =', status) with w.indent(): for (i, cond) in enumerate(conds): w('"<p style=\\"white-space:nowrap\\">{}</p>"{}', cond, ' +' if i < len(conds) - 1 else '') w('),') w('}})') params = codeForParams(rp.query_param, scope) with java.Method(w, 'public', 'Object', method_name, params): w('return {}.{}({});', java.mixedCase(endpt.attrs['interface'].s), method_name, ', '.join('\v' + p for (_, p) in params))