All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wordnik.swagger.codegen.BasicGenerator.scala Maven / Gradle / Ivy

/**
 *  Copyright 2013 Wordnik, Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.wordnik.swagger.codegen

import com.wordnik.swagger.codegen._
import com.wordnik.swagger.codegen.util._
import com.wordnik.swagger.codegen.language.CodegenConfig
import com.wordnik.swagger.codegen.spec.SwaggerSpecValidator
import com.wordnik.swagger.model._
import com.wordnik.swagger.model.SwaggerSerializers
import com.wordnik.swagger.codegen.spec.ValidationMessage

import java.io.{ File, FileWriter }

import scala.io._
import scala.collection.JavaConversions._
import scala.collection.mutable.{ ListBuffer, HashMap, HashSet }
import scala.io.Source

abstract class BasicGenerator extends CodegenConfig with PathUtil {
  def packageName = "com.wordnik.client"
  def templateDir = "src/main/resources/scala"
  def destinationDir = "generated-code/src/main/scala"
  def fileSuffix = ".scala"

  override def invokerPackage: Option[String] = Some("com.wordnik.client.common")
  override def modelPackage: Option[String] = Some("com.wordnik.client.model")
  override def apiPackage: Option[String] = Some("com.wordnik.client.api")

  var codegen = new Codegen(this)

  def generateClient(args: Array[String]) = {
    generateClientWithoutExit(args)
    System.exit(0)
  }

  def generateClientWithoutExit(args: Array[String]) {
    if (args.length == 0) {
      throw new RuntimeException("Need url to resource listing as argument. You can also specify VM Argument -DfileMap=/path/to/folder/containing.resources.json/")
    }
    val host = args(0)
    val authorization = {
      Option(System.getProperty("header")) match {
        case Some(e) => {
          // this is ugly and will be replaced with proper arg parsing like in ScalaAsyncClientGenerator soon
          val authInfo = e.split(":")
          Some(ApiKeyValue(authInfo(0), "header", authInfo(1)))
        }
        case _ => {
          if (args.length > 1) {
            Some(ApiKeyValue("api_key", "query", args(1)))
          }
          else None
        }
      }
    }
    val doc = {
      try {
        ResourceExtractor.fetchListing(getResourcePath(host), authorization)
      } catch {
        case e: Exception => throw new Exception("unable to read from " + host, e)
      }
    }

    implicit val basePath = getBasePath(host, doc.basePath)
    println("base path is " + basePath)

    val apiReferences = doc.apis
    if (apiReferences == null)
      throw new Exception("No APIs specified by resource")
    val apis = ApiExtractor.fetchApiListings(doc.swaggerVersion, basePath, apiReferences, authorization)

    SwaggerSerializers.validationMessages.filter(_.level == ValidationMessage.ERROR).size match {
      case i: Int if i > 0 => {
        println("********* Failed to read swagger json!")
        SwaggerSerializers.validationMessages.foreach(msg => {
          println(msg)
        })
        Option(System.getProperty("skipErrors")) match {
          case Some(str) => println("**** ignoring errors and continuing")
          case None => sys.exit(0)
        }
      }
      case 0 =>
    }

    new SwaggerSpecValidator(doc, apis).validate()

    val allModels = new HashMap[String, Model]
    val operations = extractApiOperations(apis, allModels)
    val operationMap = groupOperationsToFiles(operations)
    val modelBundle = prepareModelMap(allModels.toMap)
    val modelFiles = bundleToSource(modelBundle, modelTemplateFiles.toMap)

    modelFiles.map(m => {
      val filename = m._1

      val file = new java.io.File(filename)
      file.getParentFile().mkdirs

      val fw = new FileWriter(filename, false)
      fw.write(m._2 + "\n")
      fw.close()
      println("wrote model " + filename)
    })

    val apiBundle = prepareApiBundle(operationMap.toMap)
    val apiFiles = bundleToSource(apiBundle, apiTemplateFiles.toMap)

    apiFiles.map(m => {
      val filename = m._1

      val file = new java.io.File(filename)
      file.getParentFile().mkdirs

      val fw = new FileWriter(filename, false)
      fw.write(m._2 + "\n")
      fw.close()
      println("wrote api " + filename)
    })

    codegen.writeSupportingClasses(operationMap, allModels.toMap)
  }

  def extractApiOperations(apiListings: List[ApiListing], allModels: HashMap[String, Model] )(implicit basePath:String) = {
    val output = new ListBuffer[(String, String, Operation)]
    apiListings.foreach(apiDescription => {
      val basePath = apiDescription.basePath
      val resourcePath = apiDescription.resourcePath
      if(apiDescription.apis != null) {
        apiDescription.apis.foreach(api => {
          for ((apiPath, operation) <- ApiExtractor.extractApiOperations(basePath, api)) {
            output += Tuple3(basePath, apiPath, operation)
          }
        })
      }
      output.map(op => processApiOperation(op._2, op._3))
      allModels ++= CoreUtils.extractApiModels(apiDescription)
    })
    output.toList
  }

  /**
   * creates a map of models and properties needed to write source
   */
  def prepareModelMap(models: Map[String, Model]): List[Map[String, AnyRef]] = {
    (for ((name, schema) <- models) yield {
      if (!defaultIncludes.contains(name)) {
        val m = new HashMap[String, AnyRef]
        m += "name" -> toModelName(name)
        m += "className" -> name
        m += "filename" -> toModelFilename(name)
        m += "apis" -> None
        m += "models" -> List((name, schema))
        m += "package" -> modelPackage
        m += "invokerPackage" -> invokerPackage
        m += "outputDirectory" -> (destinationDir + File.separator + modelPackage.getOrElse("").replace(".", File.separator))
        m += "newline" -> "\n"

        Some(m.toMap)
      }
      else None
    }).flatten.toList
  }

  def prepareApiBundle(apiMap: Map[(String, String), List[(String, Operation)]] ): List[Map[String, AnyRef]] = {
    (for ((identifier, operationList) <- apiMap) yield {
      val basePath = identifier._1
      val name = identifier._2
      val className = toApiName(name)

      val m = new HashMap[String, AnyRef]

      m += "baseName" -> name
      m += "filename" -> toApiFilename(name)
      m += "name" -> toApiName(name)
      m += "className" -> className
      m += "basePath" -> basePath
      m += "package" -> apiPackage
      m += "invokerPackage" -> invokerPackage
      m += "apis" -> Map(className -> operationList.toList)
      m += "models" -> None
      m += "outputDirectory" -> (destinationDir + File.separator + apiPackage.getOrElse("").replace(".", File.separator))
      m += "newline" -> "\n"

      Some(m.toMap)
    }).flatten.toList
  }

  def bundleToSource(bundle:List[Map[String, AnyRef]], templates: Map[String, String]): List[(String, String)] = {
    val output = new ListBuffer[(String, String)]
    bundle.foreach(m => {
      for ((file, suffix) <- templates) {
        output += Tuple2(m("outputDirectory").toString + File.separator + m("filename").toString + suffix, codegen.generateSource(m, file))
      }
    })
    output.toList
  }

  def generateAndWrite(bundle: Map[String, AnyRef], templateFile: String) = {
    val output = codegen.generateSource(bundle, templateFile)
    val outputDir = new File(bundle("outputDirectory").asInstanceOf[String])
    outputDir.mkdirs

    val filename = outputDir + File.separator + bundle("filename")
    val fw = new FileWriter(filename, false)
    fw.write(output + "\n")
    fw.close()
    println("wrote " + filename)
  }

  def groupOperationsToFiles(operations: List[(String, String, Operation)]): Map[(String, String), List[(String, Operation)]] = {
    val opMap = new HashMap[(String, String), ListBuffer[(String, Operation)]]
    for ((basePath, apiPath, operation) <- operations) {
      val className = resourceNameFromFullPath(apiPath)
      val listToAddTo = opMap.getOrElse((basePath, className), {
        val l = new ListBuffer[(String, Operation)]
        opMap += (basePath, className) -> l
        l
      })
      listToAddTo += Tuple2(apiPath, operation)
    }
    opMap.map(m => (m._1, m._2.toList)).toMap
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy