Esempio n. 1
0
func typeStack(registry rdl.TypeRegistry, typeDef *rdl.Type) []*rdl.Type {
	var types []*rdl.Type
	types = append(types, typeDef)
	tName, tType, _ := rdl.TypeInfo(typeDef)
	for tName != rdl.TypeName(tType) {
		supertype := registry.FindType(tType)
		types = append(types, supertype)
		tName, tType, _ = rdl.TypeInfo(supertype)
	}
	return types
}
Esempio n. 2
0
// GenerateJavaModel generates the model code for the types defined in the RDL schema.
func GenerateJavaModel(banner string, schema *rdl.Schema, outdir string, ns string) error {
	packageDir, err := javaGenerationDir(outdir, schema, ns)
	if err != nil {
		return err
	}
	registry := rdl.NewTypeRegistry(schema)
	for _, t := range schema.Types {
		tName, _, _ := rdl.TypeInfo(t)
		if strings.HasPrefix(string(tName), "rdl.") {
			continue
		}
		err := generateJavaType(banner, schema, registry, packageDir, t, ns)
		if err != nil {
			return err
		}
	}
	cName := capitalize(string(schema.Name)) + "Schema"
	out, file, _, err := outputWriter(packageDir, cName, ".java")
	if err != nil {
		return err
	}
	err = javaGenerateSchema(schema, cName, out, ns, banner)
	out.Flush()
	file.Close()
	if err != nil {
		return err
	}
	return nil
}
Esempio n. 3
0
func formatNumberType(out io.Writer, registry rdl.TypeRegistry, name string, types []*rdl.Type) {
	var options [][]string
	var minVal, maxVal *[]string
	baseType, _, _ := rdl.TypeInfo(types[len(types)-1])
	topType := types[0].NumberTypeDef
	for i := len(types) - 1; i >= 0; i-- {
		switch types[i].Variant {
		case rdl.TypeVariantNumberTypeDef:
			t := types[i].NumberTypeDef
			c := ""
			if t != topType {
				c = "[from [" + string(t.Name) + "](#" + strings.ToLower(string(t.Name)) + ")]"
			}
			if t.Min != nil {
				minVal = &[]string{"min", fmt.Sprintf("%v", *t.Min), c}
			}
			if t.Max != nil {
				maxVal = &[]string{"max", fmt.Sprintf("%v", *t.Max), c}
			}
		}
	}
	if minVal != nil {
		options = append(options, *minVal)
	}
	if maxVal != nil {
		options = append(options, *maxVal)
	}
	if len(options) > 0 {
		fmt.Fprintf(out, "`%s` is a `%s` type with the following options:\n\n", name, baseType)
		formatTable(out, []string{"Option", "Value", "Notes"}, options)
	} else {
		fmt.Fprintf(out, "`%s` is a `%s` type.\n\n", topType.Name, baseType)
	}
}
Esempio n. 4
0
func (gen *modelGenerator) requiredImports(t *rdl.Type, imports map[string]string, visited map[rdl.TypeName]rdl.TypeName) {
	tName, _, _ := rdl.TypeInfo(t)
	if _, ok := visited[tName]; ok {
		return
	}
	visited[tName] = tName
	if strings.HasPrefix(string(tName), "rdl.") && !gen.rdl {
		imports[gen.librdl] = "rdl"
	}
	b := gen.registry.BaseType(t)
	switch b {
	case rdl.BaseTypeTimestamp, rdl.BaseTypeUUID:
		if !gen.rdl {
			imports[gen.librdl] = "rdl"
		}
	case rdl.BaseTypeEnum:
		imports["encoding/json"] = ""
		imports["fmt"] = ""
		break
	case rdl.BaseTypeUnion:
		imports["encoding/json"] = ""
		imports["fmt"] = ""
		break
	case rdl.BaseTypeArray:
		if t.ArrayTypeDef != nil {
			gen.requiredImports(gen.registry.FindType(t.ArrayTypeDef.Items), imports, visited)
		}
	case rdl.BaseTypeMap:
		if t.MapTypeDef != nil {
			gen.requiredImports(gen.registry.FindType(t.MapTypeDef.Keys), imports, visited)
			gen.requiredImports(gen.registry.FindType(t.MapTypeDef.Items), imports, visited)
		}
	case rdl.BaseTypeStruct:
		if !gen.rdl {
			imports[gen.librdl] = "rdl"
		}
		imports["encoding/json"] = ""
		if t.StructTypeDef != nil && t.StructTypeDef.Fields != nil {
			for _, f := range t.StructTypeDef.Fields {
				if !f.Optional {
					switch gen.registry.FindBaseType(f.Type) {
					case rdl.BaseTypeString, rdl.BaseTypeArray, rdl.BaseTypeMap, rdl.BaseTypeStruct:
						imports["fmt"] = ""
					}
				}
				if f.Items != "" {
					gen.requiredImports(gen.registry.FindType(f.Items), imports, visited)
				} else if f.Keys != "" {
					gen.requiredImports(gen.registry.FindType(f.Keys), imports, visited)
				} else {
					t := gen.registry.FindType(f.Type)
					if t != nil {
						gen.requiredImports(t, imports, visited)
					}
				}
			}
		}
	}
}
Esempio n. 5
0
func (gen *javaModelGenerator) emitTypeComment(t *rdl.Type) {
	tName, _, tComment := rdl.TypeInfo(t)
	s := string(tName) + " -"
	if tComment != "" {
		s += " " + tComment
	}
	gen.emit(formatComment(s, 0, 80))
}
Esempio n. 6
0
func annotate(registry rdl.TypeRegistry, typename rdl.TypeRef) string {
	t := registry.FindType(typename)
	if t != nil {
		tName, tType, _ := rdl.TypeInfo(t)
		if tType != rdl.TypeRef(tName) {
			return "[" + string(typename) + "](#" + strings.ToLower(string(typename)) + ")"
		}
	}
	return string(typename)
}
Esempio n. 7
0
func (gen *javaModelGenerator) emitArray(t *rdl.Type) {
	if gen.err == nil {
		switch t.Variant {
		case rdl.TypeVariantArrayTypeDef:
			at := t.ArrayTypeDef
			gen.emitTypeComment(t)
			ftype := javaType(gen.registry, at.Type, false, at.Items, "")
			gen.emit(fmt.Sprintf("type %s %s\n\n", at.Name, ftype))
		default:
			tName, tType, _ := rdl.TypeInfo(t)
			gtype := javaType(gen.registry, tType, false, "", "")
			gen.emitTypeComment(t)
			gen.emit(fmt.Sprintf("type %s %s\n\n", tName, gtype))
		}
	}
}
Esempio n. 8
0
func (gen *modelGenerator) emitMap(t *rdl.Type) {
	if gen.err == nil {
		switch t.Variant {
		case rdl.TypeVariantMapTypeDef:
			mt := t.MapTypeDef
			gen.emitTypeComment(t)
			ftype := goType(gen.registry, mt.Type, false, mt.Items, mt.Keys, gen.precise, false)
			gen.emit(fmt.Sprintf("type %s %s\n\n", mt.Name, ftype))
		default:
			tName, tType, _ := rdl.TypeInfo(t)
			gtype := goType(gen.registry, tType, false, "string", "", gen.precise, false)
			gen.emitTypeComment(t)
			gen.emit(fmt.Sprintf("type %s %s\n\n", tName, gtype))
		}
	}
}
Esempio n. 9
0
func generateJavaType(banner string, schema *rdl.Schema, registry rdl.TypeRegistry, outdir string, t *rdl.Type, ns string) error {
	tName, _, _ := rdl.TypeInfo(t)
	bt := registry.BaseType(t)
	switch bt {
	case rdl.BaseTypeStruct:
	case rdl.BaseTypeUnion:
	case rdl.BaseTypeEnum:
	default:
		return nil
	}
	cName := capitalize(string(tName))
	out, file, _, err := outputWriter(outdir, cName, ".java")
	if err != nil {
		return err
	}
	if file != nil {
		defer file.Close()
	}
	gen := &javaModelGenerator{registry, schema, string(tName), out, nil, ns, true}
	gen.emitHeader(banner, ns, bt, t)
	switch bt {
	case rdl.BaseTypeStruct:
		gen.emit("\n")
		gen.emitStruct(t, cName)
	case rdl.BaseTypeUnion:
		gen.emit("\n")
		gen.emitUnion(t)
	case rdl.BaseTypeArray:
		gen.emit("\n")
		gen.emitArray(t)
	case rdl.BaseTypeEnum:
		gen.emit("\n")
		gen.emitTypeComment(t)
		gen.emitEnum(t)
	}
	out.Flush()
	return gen.err
}
Esempio n. 10
0
func (gen *modelGenerator) emitType(t *rdl.Type) {
	if gen.err == nil {
		tName, _, _ := rdl.TypeInfo(t)
		if strings.HasPrefix(string(tName), "rdl.") {
			return
		}
		tName = rdl.TypeName(goTypeName(tName))
		bt := gen.registry.BaseType(t)
		switch bt {
		case rdl.BaseTypeAny:
			gen.emit("\n")
			gen.emitTypeComment(t)
			gen.emit(fmt.Sprintf("type %s interface{}\n", tName))
		case rdl.BaseTypeString, rdl.BaseTypeBool, rdl.BaseTypeInt8, rdl.BaseTypeInt16, rdl.BaseTypeInt32, rdl.BaseTypeInt64, rdl.BaseTypeFloat32, rdl.BaseTypeFloat64, rdl.BaseTypeSymbol:
			if gen.precise {
				gen.emit("\n")
				gen.emitTypeComment(t)
				gen.emit(fmt.Sprintf("type %s %s\n", tName, goType(gen.registry, rdl.TypeRef(bt.String()), false, "", "", gen.precise, false)))
			}
		case rdl.BaseTypeStruct:
			gen.emit("\n")
			gen.emitStruct(t)
		case rdl.BaseTypeUnion:
			gen.emit("\n")
			gen.emitUnion(t)
		case rdl.BaseTypeArray:
			gen.emit("\n")
			gen.emitArray(t)
		case rdl.BaseTypeMap:
			gen.emit("\n")
			gen.emitMap(t)
		case rdl.BaseTypeEnum:
			gen.emit("\n")
			gen.emitTypeComment(t)
			gen.emitEnum(t)
		}
	}
}
Esempio n. 11
0
func formatType(out io.Writer, registry rdl.TypeRegistry, typeDef *rdl.Type) {
	tName, _, tComment := rdl.TypeInfo(typeDef)
	fmt.Fprintf(out, "\n### %s\n", tName)
	if tComment != "" {
		fmt.Fprintf(out, "%s", formatBlock(tComment, 0, 80, ""))
	}
	types := typeStack(registry, typeDef)
	name := string(tName)
	switch typeDef.Variant {
	case rdl.TypeVariantStringTypeDef:
		formatStringType(out, registry, name, types)
	case rdl.TypeVariantNumberTypeDef:
		formatNumberType(out, registry, name, types)
	case rdl.TypeVariantStructTypeDef:
		formatStructType(out, registry, types)
	case rdl.TypeVariantUnionTypeDef:
		tt := typeDef.UnionTypeDef
		formatUnionType(out, registry, tt)
	case rdl.TypeVariantEnumTypeDef:
		tt := typeDef.EnumTypeDef
		formatEnumType(out, registry, tt)
	case rdl.TypeVariantArrayTypeDef:
		tt := typeDef.ArrayTypeDef
		name = name + "<" + string(tt.Items) + ">"
		formatArrayType(out, registry, name, types)
	case rdl.TypeVariantMapTypeDef:
		tt := typeDef.MapTypeDef
		name = name + "<" + string(tt.Keys) + "," + string(tt.Items) + ">"
		formatMapType(out, registry, name, types)
	case rdl.TypeVariantAliasTypeDef:
		formatAliasType(out, registry, typeDef.AliasTypeDef)
	case rdl.TypeVariantBytesTypeDef:
		formatBytesType(out, registry, name, types)
	case rdl.TypeVariantBaseType:
		//never happens
	}
}
Esempio n. 12
0
func (gen *modelGenerator) emitUnion(t *rdl.Type) {
	tName, _, _ := rdl.TypeInfo(t)
	ut := t.UnionTypeDef
	uName := capitalize(string(tName))
	gen.emit(fmt.Sprintf("//\n// %sVariantTag - generated to support %s\n//\n", uName, uName))
	gen.emit(fmt.Sprintf("type %sVariantTag int\n\n", uName))
	gen.emit("//\n// Supporting constants\n//\n")
	gen.emit("const (\n")
	gen.emit(fmt.Sprintf("\t_ %sVariantTag = iota\n", uName))
	for _, v := range ut.Variants {
		uV := capitalize(string(v))
		gen.emit(fmt.Sprintf("\t%sVariant%s\n", uName, uV))
	}
	gen.emit(")\n\n")

	maxKeyLen := len("Variant")
	for _, v := range ut.Variants {
		if len(v) > maxKeyLen {
			maxKeyLen = len(v)
		}
	}
	gen.emitTypeComment(t)
	gen.emit(fmt.Sprintf("type %s struct {\n", uName))
	s := leftJustified("Variant", maxKeyLen)
	vtag := uName + "VariantTag"
	gen.emit(fmt.Sprintf("\t%s %s `json:\"-\" rdl:\"union\"`\n", s, vtag))
	maxVarLen := maxKeyLen + 1
	if len(vtag) > maxVarLen {
		maxVarLen = len(vtag)
	}
	for _, v := range ut.Variants {
		uV := capitalize(string(v))
		vType := goType(gen.registry, v, true, "", "", gen.precise, true)
		tag := fmt.Sprintf("`json:\"%s,omitempty\"`", v)
		s := leftJustified(uV, maxKeyLen)
		gen.emit(fmt.Sprintf("\t%s %s %s\n", s, leftJustified(vType, maxVarLen), tag))
	}
	gen.emit("}\n\n")
	gen.emit(fmt.Sprintf("func (u %s) String() string {\n", uName))
	gen.emit("\tswitch u.Variant {\n")
	for _, v := range ut.Variants {
		uV := capitalize(string(v))
		gen.emit(fmt.Sprintf("\tcase %sVariant%s:\n", uName, uV))
		gen.emit(fmt.Sprintf("\t\treturn fmt.Sprintf(\"%%v\", u.%s)\n", uV))
	}
	gen.emit("\tdefault:\n")
	gen.emit(fmt.Sprintf("\t\treturn \"<%s uninitialized>\"\n", uName))
	gen.emit("\t}\n")
	gen.emit("}\n\n")
	gen.emit(fmt.Sprintf("//\n// Validate for %s\n//\n", uName))
	gen.emit(fmt.Sprintf("func (p *%s) Validate() error {\n", uName))
	gen.emit("\t")
	for _, v := range ut.Variants {
		gen.emit(fmt.Sprintf("if p.%s != nil {\n\t\tp.Variant = %sVariant%s\n\t} else ", v, uName, v))
	}
	gen.emit(fmt.Sprintf("{\n\t\treturn fmt.Errorf(\"%s: Missing required variant\")\n\t}\n", uName))
	gen.emit("\treturn nil\n")
	gen.emit("}\n")

	if gen.isUntaggedUnion(tName) {
		gen.emitUntaggedUnionSerializer(ut, tName)
	} else {
		gen.emit(fmt.Sprintf("\ntype raw%s %s\n\n", uName, uName))
		gen.emit(fmt.Sprintf("//\n// UnmarshalJSON for %s\n//\n", uName))
		gen.emit(fmt.Sprintf("func (p *%s) UnmarshalJSON(b []byte) error {\n", uName))
		gen.emit(fmt.Sprintf("\tvar tmp raw%s\n", uName))
		gen.emit("\tif err := json.Unmarshal(b, &tmp); err != nil {\n")
		gen.emit("\t\treturn err\n")
		gen.emit("\t}\n")
		gen.emit(fmt.Sprintf("\t*p = %s(tmp)\n", uName))
		gen.emit("\treturn p.Validate()\n")
		gen.emit("}\n")
	}
}
Esempio n. 13
0
func swagger(schema *rdl.Schema) (*SwaggerDoc, error) {
	reg := rdl.NewTypeRegistry(schema)
	sname := string(schema.Name)
	swag := new(SwaggerDoc)
	swag.Swagger = "2.0"
	swag.Schemes = []string{"http"}
	//swag.Host = "localhost"
	swag.BasePath = "/api"

	title := "API"
	if sname != "" {
		title = "The " + sname + " API"
		swag.BasePath = "/api/" + sname
	}
	swag.Info = new(SwaggerInfo)
	swag.Info.Title = title
	if schema.Version != nil {
		swag.Info.Version = fmt.Sprintf("%d", *schema.Version)
		swag.BasePath += "/v" + fmt.Sprintf("%d", *schema.Version)
	}
	if schema.Comment != "" {
		swag.Info.Description = schema.Comment
	}
	if len(schema.Resources) > 0 {
		paths := make(map[string]map[string]*SwaggerAction)
		for _, r := range schema.Resources {
			path := r.Path
			actions, ok := paths[path]
			if !ok {
				actions = make(map[string]*SwaggerAction)
				paths[path] = actions
			}
			meth := strings.ToLower(r.Method)
			action, ok := actions[meth]
			if !ok {
				action = new(SwaggerAction)
			}
			action.Summary = r.Comment
			tag := string(r.Type)       //fixme: RDL has no tags, the type is actually too fine grain for this
			action.Tags = []string{tag} //multiple tags include the resource in multiple sections
			action.Produces = []string{"application/json"}
			var ins []*SwaggerParameter
			if len(r.Inputs) > 0 {
				if r.Method == "POST" || r.Method == "PUT" {
					action.Consumes = []string{"application/json"}
				}
				for _, in := range r.Inputs {
					param := new(SwaggerParameter)
					param.Name = string(in.Name)
					param.Description = in.Comment
					required := true
					if in.Optional {
						required = false
					}
					param.Required = required
					if in.PathParam {
						param.In = "path"
					} else if in.QueryParam != "" {
						param.In = "query"
						param.Name = in.QueryParam //swagger has no formal arg concept
					} else if in.Header != "" {
						//swagger has no header params
						continue
					} else {
						param.In = "body"
					}
					ptype, pformat, ref := makeSwaggerTypeRef(reg, in.Type)
					param.Type = ptype
					param.Format = pformat
					param.Schema = ref
					ins = append(ins, param)
				}
				action.Parameters = ins
			}
			responses := make(map[string]*SwaggerResponse)
			expected := r.Expected
			addSwaggerResponse(responses, string(r.Type), expected, "")
			if len(r.Alternatives) > 0 {
				for _, alt := range r.Alternatives {
					addSwaggerResponse(responses, string(r.Type), alt, "")
				}
			}
			if len(r.Exceptions) > 0 {
				for sym, errdef := range r.Exceptions {
					errType := errdef.Type //xxx
					addSwaggerResponse(responses, errType, sym, errdef.Comment)
				}
			}
			action.Responses = responses
			//responses -> r.expected and r.exceptions
			//security -> r.auth
			//r.outputs?
			//action.description?
			//action.operationId IGNORE

			actions[meth] = action
			paths[path] = actions
		}
		swag.Paths = paths
	}
	if len(schema.Types) > 0 {
		defs := make(map[string]*SwaggerType)
		for _, t := range schema.Types {
			ref := makeSwaggerTypeDef(reg, t)
			if ref != nil {
				tName, _, _ := rdl.TypeInfo(t)
				defs[string(tName)] = ref
			}
		}
		if true {
			props := make(map[string]*SwaggerType)
			codeType := new(SwaggerType)
			t := "integer"
			codeType.Type = t
			f := "int32"
			codeType.Format = f
			props["code"] = codeType
			msgType := new(SwaggerType)
			t2 := "string"
			msgType.Type = t2
			props["message"] = msgType
			prop := new(SwaggerType)
			prop.Required = []string{"code", "message"}
			prop.Properties = props
			defs["ResourceError"] = prop
		}
		swag.Definitions = defs
	}
	return swag, nil
}