From f4c8dd9dec25dee7cbb604b47056c0aa8f7f41f6 Mon Sep 17 00:00:00 2001 From: Tony Tam Date: Mon, 27 Aug 2012 17:30:25 -0700 Subject: [PATCH] added invoker package, updated writing supporting files --- .../swagger/codegen/BasicGenerator.scala | 6 +- .../com/wordnik/swagger/codegen/Codegen.scala | 102 +++++++++++++++--- .../codegen/language/CodegenConfig.scala | 1 + 3 files changed, 93 insertions(+), 16 deletions(-) diff --git a/src/main/scala/com/wordnik/swagger/codegen/BasicGenerator.scala b/src/main/scala/com/wordnik/swagger/codegen/BasicGenerator.scala index 17159edabbb..4f6115793b4 100644 --- a/src/main/scala/com/wordnik/swagger/codegen/BasicGenerator.scala +++ b/src/main/scala/com/wordnik/swagger/codegen/BasicGenerator.scala @@ -96,7 +96,7 @@ abstract class BasicGenerator extends CodegenConfig with PathUtil { val map = new HashMap[String, AnyRef] map += "basePath" -> basePath map += "package" -> apiPackage - map += "invokerPackage" -> Some(packageName) + map += "invokerPackage" -> invokerPackage map += "apis" -> Map(className -> operationList.toList) map += "models" -> None map += "outputDirectory" -> (destinationDir + File.separator + apiPackage.getOrElse("").replaceAll("\\.", File.separator)) @@ -113,7 +113,7 @@ abstract class BasicGenerator extends CodegenConfig with PathUtil { map += "apis" -> None map += "models" -> List((name, schema)) map += "package" -> modelPackage - map += "invokerPackage" -> Some(packageName) + map += "invokerPackage" -> invokerPackage map += "outputDirectory" -> (destinationDir + File.separator + modelPackage.getOrElse("").replaceAll("\\.", File.separator)) map += "newline" -> "\n" modelBundleList += map.toMap @@ -122,7 +122,7 @@ abstract class BasicGenerator extends CodegenConfig with PathUtil { generateAndWrite(map.toMap, file) } } - codegen.writeSupportingClasses + codegen.writeSupportingClasses(apiMap.toMap, allModels.toMap) } def apiNameFromPath(apiPath: String) = makeApiNameFromPath(apiPath) diff --git a/src/main/scala/com/wordnik/swagger/codegen/Codegen.scala b/src/main/scala/com/wordnik/swagger/codegen/Codegen.scala index 8bcadc86f36..6e689cb3718 100644 --- a/src/main/scala/com/wordnik/swagger/codegen/Codegen.scala +++ b/src/main/scala/com/wordnik/swagger/codegen/Codegen.scala @@ -17,7 +17,6 @@ package com.wordnik.swagger.codegen import com.wordnik.swagger.core._ - import com.wordnik.swagger.codegen.util.{ CoreUtils, ScalaJsonUtil } import com.wordnik.swagger.codegen.language.CodegenConfig import com.wordnik.swagger.codegen.spec.SwaggerSpec._ @@ -29,11 +28,12 @@ import org.fusesource.scalate.support.ScalaCompiler import java.io.File import java.io.FileWriter +import java.io.InputStream +import org.apache.commons.io.FileUtils import scala.io.Source import scala.collection.mutable.{ HashMap, ListBuffer, HashSet } import scala.collection.JavaConversions._ -import org.apache.commons.io.FileUtils object Codegen { val templates = new HashMap[String, (TemplateEngine, Template)] @@ -121,9 +121,16 @@ class Codegen(config: CodegenConfig) { val engineData = Codegen.templates.getOrElse(templateFile, { val engine = new TemplateEngine(Some(rootDir)) val srcName = config.templateDir + File.separator + templateFile - val srcStream = getClass.getClassLoader.getResourceAsStream(srcName) - if (srcStream == null) - throw new Exception("Missing template: " + srcName) + val srcStream = { + getClass.getClassLoader.getResourceAsStream(srcName) match { + case is: java.io.InputStream => is + case _ => { + val f = new java.io.File(srcName) + if (!f.exists) throw new Exception("Missing template: " + srcName) + else new java.io.FileInputStream(f) + } + } + } println("pre-compile") val template = engine.compile( TemplateSource.fromText(config.templateDir + File.separator + templateFile, @@ -170,12 +177,25 @@ class Codegen(config: CodegenConfig) { imports.toSet } + def stringify(v: DocumentationAllowableValues) = { + v match { + case av: DocumentationAllowableListValues => { + av.getValueType + av.getValues.mkString("[", ",", "]") + } + case av: DocumentationAllowableRangeValues => { + av.getValueType + "[" + av.getMin() + "," + av.getMax() + "]" + } + case _ => "unsupported" + } + } + def apiToMap(path: String, op: DocumentationOperation): Map[String, AnyRef] = { var bodyParam: Option[String] = None var queryParams = new ListBuffer[AnyRef] val pathParams = new ListBuffer[AnyRef] val headerParams = new ListBuffer[AnyRef] + val bodyParams = new ListBuffer[AnyRef] var paramList = new ListBuffer[HashMap[String, AnyRef]] if (op.getParameters != null) { @@ -186,6 +206,13 @@ class Codegen(config: CodegenConfig) { params += "dataType" -> config.toDeclaredType(param.dataType) params += "description" -> param.description params += "hasMore" -> "true" + params += "allowMultiple" -> param.allowMultiple.toString + + param.allowableValues match { + case a: DocumentationAllowableValues => params += "allowableValues" -> stringify(a) + case _ => + } + if (!param.required) { params += "optional" -> "true" } @@ -198,6 +225,7 @@ class Codegen(config: CodegenConfig) { case _ => } bodyParam = Some("body") + bodyParams += params.clone } case "path" => { params += "paramName" -> config.toVarName(param.name) @@ -241,6 +269,11 @@ class Codegen(config: CodegenConfig) { case _ => queryParams.last.asInstanceOf[HashMap[String, String]] -= "hasMore" } + pathParams.size match { + case 0 => + case _ => pathParams.last.asInstanceOf[HashMap[String, String]] -= "hasMore" + } + val sp = { val lb = new ListBuffer[AnyRef] paramList.foreach(i => { @@ -276,6 +309,7 @@ class Codegen(config: CodegenConfig) { "deprecated" -> op.deprecated, "bodyParam" -> bodyParam, "allParams" -> sp, + "bodyParams" -> bodyParams, "pathParams" -> pathParams, "queryParams" -> queryParams, "headerParams" -> headerParams, @@ -394,13 +428,50 @@ class Codegen(config: CodegenConfig) { data.toMap } - def writeSupportingClasses = { + /** + * gets an input stream from resource or file + */ + def getInputStream(path: String): InputStream = { + getClass.getClassLoader.getResourceAsStream(path) match { + case is: InputStream => is + case _ => new java.io.FileInputStream(path) + } + } + + def writeSupportingClasses(apis: Map[(String, String), scala.collection.mutable.ListBuffer[(String, com.wordnik.swagger.core.DocumentationOperation)]], models: Map[String, DocumentationSchema]) = { val rootDir = new java.io.File(".") val engine = new TemplateEngine(Some(rootDir)) - val data: HashMap[String, String] = + val apiList = new ListBuffer[Map[String, AnyRef]] + + apis.foreach(a => { + apiList += Map( + "name" -> a._1._2, + "basePath" -> a._1._1, + "operations" -> { + (for (t <- a._2) yield { Map("operation" -> t._2, "path" -> t._1) }).toList + }) + }) + + val modelList = new ListBuffer[HashMap[String, AnyRef]] + + models.foreach(m => { + modelList += HashMap( + "modelName" -> m._1, + "model" -> m._2, + "modelJson" -> ScalaJsonUtil.getJsonMapper.writeValueAsString(m._2), + "hasMore" -> "true") + }) + modelList.size match { + case 0 => + case _ => modelList.last.asInstanceOf[HashMap[String, String]] -= "hasMore" + } + + val data: HashMap[String, AnyRef] = HashMap( - "package" -> config.packageName) + "package" -> config.packageName, + "apis" -> apiList, + "models" -> modelList) config.supportingFiles.map(file => { val srcTemplate = file._1 @@ -414,12 +485,12 @@ class Codegen(config: CodegenConfig) { if (srcTemplate.endsWith(".mustache")) { val output = { val resourceName = config.templateDir + File.separator + srcTemplate - val resourceStream = getClass.getClassLoader.getResourceAsStream(resourceName) - if (resourceStream == null) + val is = getInputStream(resourceName) + if (is == null) throw new Exception("Resource not found: " + resourceName) val template = engine.compile( TemplateSource.fromText(resourceName, - Source.fromInputStream(resourceStream).mkString)) + Source.fromInputStream(is).mkString)) engine.layout(resourceName, template, data.toMap) } val fw = new FileWriter(outputFilename, false) @@ -427,8 +498,13 @@ class Codegen(config: CodegenConfig) { fw.close() println("wrote " + outputFilename) } else { - val is = getClass.getClassLoader - .getResourceAsStream(config.templateDir + File.separator + srcTemplate) + val is = getInputStream(config.templateDir + File.separator + srcTemplate) + println("copying file " + config.templateDir + File.separator + srcTemplate + " to " + outputFilename) + val outputFile = new File(outputFilename) + val parentDir = new File(outputFile.getParent) + if (parentDir != null && !parentDir.exists) { + println("making directory: " + parentDir.toString + ": " + parentDir.mkdirs) + } FileUtils.copyInputStreamToFile(is, new File(outputFilename)) println("copied " + outputFilename) is.close diff --git a/src/main/scala/com/wordnik/swagger/codegen/language/CodegenConfig.scala b/src/main/scala/com/wordnik/swagger/codegen/language/CodegenConfig.scala index 997bb557e1d..8f4a22a93da 100644 --- a/src/main/scala/com/wordnik/swagger/codegen/language/CodegenConfig.scala +++ b/src/main/scala/com/wordnik/swagger/codegen/language/CodegenConfig.scala @@ -32,6 +32,7 @@ abstract class CodegenConfig { def typeMapping = Map[String, String]() // optional configs + def invokerPackage: Option[String] = None def apiPackage: Option[String] = None def reservedWords: Set[String] = Set()