예제 #1
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
}
예제 #2
0
// GenerateGoModel generates the model code for the types defined in the RDL schema.
func GenerateGoModel(banner string, schema *rdl.Schema, outdir string, ns string, librdl string, prefixEnums bool, precise bool, untaggedUnions []string) error {
	name := strings.ToLower(string(schema.Name))
	if strings.HasSuffix(outdir, ".go") {
		name = filepath.Base(outdir)
		outdir = filepath.Dir(outdir)
	} else {
		name = name + "_model.go"
	}
	out, file, _, err := outputWriter(outdir, name, ".go")
	if err != nil {
		return err
	}
	if file != nil {
		defer file.Close()
	}
	gen := &modelGenerator{rdl.NewTypeRegistry(schema), schema, out, librdl, prefixEnums, precise, nil, untaggedUnions, ns, schema.Name == "rdl"}
	gen.emitHeader(banner)
	if gen.err == nil {
		for _, t := range schema.Types {
			gen.emitType(t)
		}
	}
	out.Flush()
	if gen.err == nil {
		gen.err = GenerateGoSchema(banner, schema, outdir, ns, librdl)
	}
	return gen.err
}
예제 #3
0
//ExportToMarkdown exports a markdown rendering of the schema
func ExportToMarkdown(schema *rdl.Schema, outdir string) error {
	out, file, _, err := outputWriter(outdir, string(schema.Name), ".md")
	if err != nil {
		return err
	}
	if file != nil {
		defer file.Close()
	}
	registry := rdl.NewTypeRegistry(schema)
	category := "schema"
	if schema.Resources != nil {
		category = "API"
	}
	title := category
	if schema.Name != "" {
		title = "The " + capitalize(string(schema.Name)) + " " + category
	} else {
		title = capitalize(category)
	}
	fmt.Fprintf(out, "# %s\n\n", title)
	if schema.Comment != "" {
		fmt.Fprintf(out, "%s", formatBlock(schema.Comment, 0, 80, ""))
	}

	var rows [][]string
	if schema.Namespace != "" {
		rows = append(rows, []string{"namespace", string(schema.Namespace)})
	}
	if schema.Version != nil {
		rows = append(rows, []string{"version", fmt.Sprintf("%d", *schema.Version)})
	}
	if len(rows) > 0 {
		fmt.Fprintf(out, "This %s has the following attributes:\n\n", category)
		formatTable(out, []string{"Attribute", "Value"}, rows)
	}

	if schema.Resources != nil {
		fmt.Fprintf(out, "\n## Resources\n")
		groups := groupResources(schema.Resources)
		for group, lstRez := range groups {
			fmt.Fprintf(out, "\n### [%s](#%s)\n", group, group)
			//too much? formatType(out, schema, schema.FindType(group))
			for _, rez := range lstRez {
				//ideally, sort by method here to be consistent
				formatResource(out, registry, rez)
			}
		}
	}

	if len(schema.Types) > 0 {
		fmt.Fprintf(out, "\n## Types\n")
		for _, typeDef := range schema.Types {
			formatType(out, registry, typeDef)
		}
	}
	out.Flush()
	return nil
}
예제 #4
0
// GenerateGoSchema generates the code to regenerate the Schema
func GenerateGoSchema(banner string, schema *rdl.Schema, outdir string, ns string, librdl string) error {
	name := strings.ToLower(string(schema.Name))
	if strings.HasSuffix(outdir, ".go") {
		name = filepath.Base(outdir)
		outdir = filepath.Dir(outdir)
	} else {
		name = name + "_schema.go"
	}
	out, file, _, err := outputWriter(outdir, name, ".go")
	if err != nil {
		return err
	}
	if file != nil {
		defer file.Close()
	}
	rdlprefix := "rdl."
	if schema.Name == "rdl" {
		rdlprefix = ""
	}
	gen := &schemaGenerator{rdl.NewTypeRegistry(schema), schema, capitalize(string(schema.Name)), out, nil, banner, ns, librdl, rdlprefix}
	gen.emit(generationHeader(banner))
	gen.emit("\n\npackage " + generationPackage(gen.schema, gen.ns) + "\n\n")
	if gen.schema.Name != "rdl" {
		gen.emit("import (\n")
		gen.emit("\trdl \"" + librdl + "\"\n")
		gen.emit(")\n\n")
	}
	gen.emit("var schema *" + rdlprefix + "Schema\n\n")
	gen.emit(fmt.Sprintf("func init() {\n\tsb := %sNewSchemaBuilder(%q)\n", rdlprefix, schema.Name))
	if schema.Version != nil {
		gen.emit(fmt.Sprintf("\tsb.Version(%d)\n", *schema.Version))
	}
	if schema.Namespace != "" {
		gen.emit(fmt.Sprintf("\tsb.Namespace(%q)\n", schema.Namespace))
	}
	if schema.Comment != "" {
		gen.emit(fmt.Sprintf("\tsb.Comment(%q)\n", schema.Comment))
	}
	gen.emit("\n")
	if gen.err == nil {
		for _, t := range schema.Types {
			gen.emitType(t)
		}
	}
	if gen.err == nil {
		for _, r := range schema.Resources {
			gen.emitResource(r)
		}
	}
	gen.emit("\tschema = sb.Build()\n")
	gen.emit("}\n\n")
	gen.emit(fmt.Sprintf("func %sSchema() *%sSchema {\n", capitalize(string(schema.Name)), rdlprefix))
	gen.emit("\treturn schema\n")
	gen.emit("}\n")
	out.Flush()
	return gen.err
}
예제 #5
0
func javaGenerateSchema(schema *rdl.Schema, cName string, writer io.Writer, ns string, banner string) error {
	reg := rdl.NewTypeRegistry(schema)
	funcMap := template.FuncMap{
		"header": func() string {
			s := fmt.Sprintf("//\n// This file generated by %s\n//\n\n", banner)
			s2 := javaGenerationPackage(schema, ns)
			if s2 != "" {
				s = s + "package " + s2 + ";\n"
			}
			if ns != "com.yahoo.rdl" {
				s = s + "import com.yahoo.rdl.*;\n"
			}
			return s
		},
		"version": func() string {
			if schema.Version != nil {
				return fmt.Sprintf("        sb.version(%d);", *schema.Version)
			} else {
				return ""
			}
		},
		"name": func() string { return string(schema.Name) },
		"namespace": func() string {
			if schema.Namespace != "" {
				return fmt.Sprintf("\n        sb.namespace(%q);", schema.Namespace)
			} else {
				return ""
			}
		},
		"comment": func() string {
			if schema.Comment != "" {
				return fmt.Sprintf("\n        sb.comment(%q);", schema.Comment)
			} else {
				return ""
			}
		},
		"cname":       func() string { return cName },
		"typeDef":     func(t *rdl.Type) string { return javaGenerateTypeConstructor(reg, t) },
		"resourceDef": func(r *rdl.Resource) string { return javaGenerateResourceConstructor(reg, r) },
	}
	t := template.Must(template.New("util").Funcs(funcMap).Parse(javaSchemaTemplate))
	return t.Execute(writer, schema)
}
예제 #6
0
// GenerateJavaClient generates the client code to talk to the server
func GenerateJavaClient(banner string, schema *rdl.Schema, outdir string, ns string, base string) error {
	reg := rdl.NewTypeRegistry(schema)
	packageDir, err := javaGenerationDir(outdir, schema, ns)
	if err != nil {
		return err
	}
	cName := capitalize(string(schema.Name))

	out, file, _, err := outputWriter(packageDir, cName, "Client.java")
	if err != nil {
		return err
	}
	gen := &javaClientGenerator{reg, schema, cName, out, nil, banner, ns, base}
	gen.processTemplate(javaClientTemplate)
	out.Flush()
	file.Close()
	if gen.err != nil {
		return gen.err
	}

	//ResourceException - the throawable wrapper for alternate return types
	out, file, _, err = outputWriter(packageDir, "ResourceException", ".java")
	if err != nil {
		return err
	}
	err = javaGenerateResourceException(schema, out, ns)
	out.Flush()
	file.Close()
	if err != nil {
		return err
	}

	//ResourceError - the default data object for an error
	out, file, _, err = outputWriter(packageDir, "ResourceError", ".java")
	if err != nil {
		return err
	}
	err = javaGenerateResourceError(schema, out, ns)
	out.Flush()
	file.Close()
	return err
}
예제 #7
0
// GenerateGoClient generates the client code to talk to the server.
func GenerateGoClient(banner string, schema *rdl.Schema, outdir string, ns string, librdl string, prefixEnums bool, precise bool) error {
	name := strings.ToLower(string(schema.Name))
	if strings.HasSuffix(outdir, ".go") {
		name = filepath.Base(outdir)
		outdir = filepath.Dir(outdir)
	} else {
		name = name + "_client.go"
	}
	out, file, _, err := outputWriter(outdir, name, ".go")
	if err != nil {
		return err
	}
	if file != nil {
		defer file.Close()
	}
	gen := &clientGenerator{rdl.NewTypeRegistry(schema), schema, capitalize(string(schema.Name)), out, nil, banner, prefixEnums, precise, ns, librdl}
	gen.emitClient()
	out.Flush()
	return gen.err
}
예제 #8
0
// GenerateJavaServer generates the server code for the RDL-defined service
func GenerateJavaServer(banner string, schema *rdl.Schema, outdir string, ns string, base string) error {
	reg := rdl.NewTypeRegistry(schema)
	packageDir, err := javaGenerationDir(outdir, schema, ns)
	if err != nil {
		return err
	}
	cName := capitalize(string(schema.Name))

	async := false
	for _, r := range schema.Resources {
		if r.Async != nil && *r.Async {
			async = true
			break
		}
	}

	//FooHandler interface
	out, file, _, err := outputWriter(packageDir, cName, "Handler.java")
	if err != nil {
		return err
	}
	gen := &javaServerGenerator{reg, schema, cName, out, nil, banner, ns, async, base}
	gen.processTemplate(javaServerHandlerTemplate)
	out.Flush()
	file.Close()

	for _, r := range schema.Resources {
		if r.Async != nil && *r.Async {
			javaServerMakeAsyncResultModel(banner, schema, reg, outdir, r, ns, base)
		} else if len(r.Outputs) > 0 {
			javaServerMakeResultModel(banner, schema, reg, outdir, r, ns, base)
		}
	}

	//ResourceContext interface
	s := "ResourceContext"
	out, file, _, err = outputWriter(packageDir, s, ".java")
	if err != nil {
		return err
	}
	gen = &javaServerGenerator{reg, schema, cName, out, nil, banner, ns, async, base}
	gen.processTemplate(javaServerContextTemplate)
	out.Flush()
	file.Close()
	if gen.err != nil {
		return gen.err
	}

	//FooResources Jax-RS glue
	out, file, _, err = outputWriter(packageDir, cName, "Resources.java")
	if err != nil {
		return err
	}
	gen = &javaServerGenerator{reg, schema, cName, out, nil, banner, ns, async, base}
	gen.processTemplate(javaServerTemplate)
	out.Flush()
	file.Close()
	if gen.err != nil {
		return gen.err
	}

	//Note: to enable jackson's pretty printer:
	//import com.fasterxml.jackson.jaxrs.annotation.JacksonFeatures;
	//import com.fasterxml.jackson.databind.SerializationFeature;
	//for each resource, add this annotation:
	//   @JacksonFeatures(serializationEnable =  { SerializationFeature.INDENT_OUTPUT })

	//FooServer - an optional server wrapper that sets up Jetty9/Jersey2 to run Foo
	out, file, _, err = outputWriter(packageDir, cName, "Server.java")
	if err != nil {
		return err
	}
	gen = &javaServerGenerator{reg, schema, cName, out, nil, banner, ns, async, base}
	gen.processTemplate(javaServerInitTemplate)
	out.Flush()
	file.Close()
	if gen.err != nil {
		return gen.err
	}

	//ResourceException - the throawable wrapper for alternate return types
	s = "ResourceException"
	out, file, _, err = outputWriter(packageDir, s, ".java")
	if err != nil {
		return err
	}
	err = javaGenerateResourceException(schema, out, ns)
	out.Flush()
	file.Close()
	if err != nil {
		return err
	}

	//ResourceError - the default data object for an error
	s = "ResourceError"
	out, file, _, err = outputWriter(packageDir, s, ".java")
	if err != nil {
		return err
	}
	err = javaGenerateResourceError(schema, out, ns)
	out.Flush()
	file.Close()
	return err
}
예제 #9
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
}