repackaged

This commit is contained in:
Tony Tam 2015-06-06 23:44:20 -07:00
parent 0c1657d744
commit 1df3ed4487
23 changed files with 1451 additions and 0 deletions

View File

@ -0,0 +1,37 @@
package io.swagger.codegen;
import io.swagger.codegen.cmd.ConfigHelp;
import io.swagger.codegen.cmd.Generate;
import io.swagger.codegen.cmd.Langs;
import io.swagger.codegen.cmd.Meta;
import io.airlift.airline.Cli;
import io.airlift.airline.Help;
/**
* User: lanwen
* Date: 24.03.15
* Time: 17:56
*
* Command line interface for swagger codegen
* use `swagger-codegen-cli.jar help` for more info
*
* @since 2.1.3-M1
*/
public class SwaggerCodegen {
public static void main(String[] args) {
Cli.CliBuilder<Runnable> builder = Cli.<Runnable>builder("swagger")
.withDescription("Swagger code generator CLI. More info on swagger.io")
.withDefaultCommand(Langs.class)
.withCommands(
Generate.class,
Meta.class,
Langs.class,
Help.class,
ConfigHelp.class
);
builder.build().parse(args).run();
}
}

View File

@ -0,0 +1,49 @@
package io.swagger.codegen.cmd;
import io.swagger.codegen.CliOption;
import io.swagger.codegen.CodegenConfig;
import io.airlift.airline.Command;
import io.airlift.airline.Option;
import java.util.ServiceLoader;
import static java.util.ServiceLoader.load;
@Command(name = "config-help", description = "Config help for chosen lang")
public class ConfigHelp implements Runnable {
@Option(name = {"-l", "--lang"}, title = "language", required = true,
description = "language to get config help for")
private String lang;
@Override
public void run() {
System.out.println();
CodegenConfig config = forName(lang);
System.out.println("CONFIG OPTIONS");
for (CliOption langCliOption : config.cliOptions()) {
System.out.println("\t" + langCliOption.getOpt());
System.out.println("\t " + langCliOption.getDescription());
System.out.println();
}
}
/**
* Tries to load config class with SPI first, then with class name directly from classpath
* @param name name of config, or full qualified class name in classpath
* @return config class
*/
private static CodegenConfig forName(String name) {
ServiceLoader<CodegenConfig> loader = load(CodegenConfig.class);
for (CodegenConfig config : loader) {
if (config.getName().equals(name)) {
return config;
}
}
// else try to load directly
try {
return (CodegenConfig) Class.forName(name).newInstance();
} catch (Exception e) {
throw new RuntimeException("Can't load config class with name ".concat(name), e);
}
}
}

View File

@ -0,0 +1,156 @@
package io.swagger.codegen.cmd;
import io.swagger.codegen.CliOption;
import io.swagger.codegen.ClientOptInput;
import io.swagger.codegen.ClientOpts;
import io.swagger.codegen.CodegenConfig;
import io.swagger.codegen.DefaultGenerator;
import io.swagger.models.Swagger;
import config.Config;
import config.ConfigParser;
import io.airlift.airline.Command;
import io.airlift.airline.Option;
import io.swagger.parser.SwaggerParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.ServiceLoader;
import static java.util.ServiceLoader.load;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
/**
* User: lanwen
* Date: 24.03.15
* Time: 20:22
*/
@Command(name = "generate", description = "Generate code with chosen lang")
public class Generate implements Runnable {
public static final Logger LOG = LoggerFactory.getLogger(Generate.class);
public static final String TEMPLATE_DIR_PARAM = "templateDir";
@Option(name = {"-v", "--verbose"}, description = "verbose mode")
private boolean verbose;
@Option(name = {"-l", "--lang"}, title = "language", required = true,
description = "client language to generate (maybe class name in classpath, required)")
private String lang;
@Option(name = {"-o", "--output"}, title = "output directory",
description = "where to write the generated files (current dir by default)")
private String output = "";
@Option(name = {"-i", "--input-spec"}, title = "spec file", required = true,
description = "location of the swagger spec, as URL or file (required)")
private String spec;
@Option(name = {"-t", "--template-dir"}, title = "template directory",
description = "folder containing the template files")
private String templateDir;
@Option(name = {"-a", "--auth"}, title = "authorization",
description = "adds authorization headers when fetching the swagger definitions remotely. " +
"Pass in a URL-encoded string of name:header with a comma separating multiple values")
private String auth;
@Option( name= {"-D"}, title = "system properties", description = "sets specified system properties in " +
"the format of name=value,name=value")
private String systemProperties;
@Option( name= {"-c", "--config"}, title = "configuration file", description = "Path to json configuration file. " +
"File content should be in a json format {\"optionKey\":\"optionValue\", \"optionKey1\":\"optionValue1\"...} " +
"Supported options can be different for each language. Run config-help -l {lang} command for language specific config options.")
private String configFile;
@Override
public void run() {
verbosed(verbose);
setSystemProperties();
ClientOptInput input = new ClientOptInput();
if (isNotEmpty(auth)) {
input.setAuth(auth);
}
CodegenConfig config = forName(lang);
config.setOutputDir(new File(output).getAbsolutePath());
if (null != templateDir) {
config.additionalProperties().put(TEMPLATE_DIR_PARAM, new File(templateDir).getAbsolutePath());
}
if(null != configFile){
Config genConfig = ConfigParser.read(configFile);
if (null != genConfig) {
for (CliOption langCliOption : config.cliOptions()) {
if (genConfig.hasOption(langCliOption.getOpt())) {
config.additionalProperties().put(langCliOption.getOpt(), genConfig.getOption(langCliOption.getOpt()));
}
}
}
}
input.setConfig(config);
Swagger swagger = new SwaggerParser().read(spec, input.getAuthorizationValues(), true);
new DefaultGenerator().opts(input.opts(new ClientOpts()).swagger(swagger)).generate();
}
private void setSystemProperties() {
if( systemProperties != null && systemProperties.length() > 0 ){
for( String property : systemProperties.split(",")) {
int ix = property.indexOf('=');
if( ix > 0 && ix < property.length()-1 ){
System.setProperty( property.substring(0, ix), property.substring(ix+1) );
}
}
}
}
/**
* If true parameter, adds system properties which enables debug mode in generator
* @param verbose - if true, enables debug mode
*/
private void verbosed(boolean verbose) {
if (!verbose) {
return;
}
LOG.info("\nVERBOSE MODE: ON. Additional debug options are injected" +
"\n - [debugSwagger] prints the swagger specification as interpreted by the codegen" +
"\n - [debugModels] prints models passed to the template engine" +
"\n - [debugOperations] prints operations passed to the template engine" +
"\n - [debugSupportingFiles] prints additional data passed to the template engine");
System.setProperty("debugSwagger", "");
System.setProperty("debugModels", "");
System.setProperty("debugOperations", "");
System.setProperty("debugSupportingFiles", "");
}
/**
* Tries to load config class with SPI first, then with class name directly from classpath
* @param name name of config, or full qualified class name in classpath
* @return config class
*/
private static CodegenConfig forName(String name) {
ServiceLoader<CodegenConfig> loader = load(CodegenConfig.class);
for (CodegenConfig config : loader) {
if (config.getName().equals(name)) {
return config;
}
}
// else try to load directly
try {
return (CodegenConfig) Class.forName(name).newInstance();
} catch (Exception e) {
throw new RuntimeException("Can't load config class with name ".concat(name), e);
}
}
}

View File

@ -0,0 +1,23 @@
package io.swagger.codegen.cmd;
import ch.lambdaj.collection.LambdaIterable;
import io.swagger.codegen.CodegenConfig;
import io.airlift.airline.Command;
import static ch.lambdaj.Lambda.on;
import static ch.lambdaj.collection.LambdaCollections.with;
import static java.util.ServiceLoader.load;
/**
* User: lanwen
* Date: 24.03.15
* Time: 20:25
*/
@Command(name = "langs", description = "Shows available langs")
public class Langs implements Runnable {
@Override
public void run() {
LambdaIterable<String> langs = with(load(CodegenConfig.class)).extract(on(CodegenConfig.class).getName());
System.out.printf("Available languages: %s%n", langs);
}
}

View File

@ -0,0 +1,144 @@
package io.swagger.codegen.cmd;
import ch.lambdaj.function.convert.Converter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.samskivert.mustache.Mustache;
import io.swagger.codegen.DefaultGenerator;
import io.swagger.codegen.SupportingFile;
import io.airlift.airline.Command;
import io.airlift.airline.Option;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
import java.util.Map;
import static ch.lambdaj.collection.LambdaCollections.with;
import static com.google.common.base.Joiner.on;
/**
* User: lanwen
* Date: 24.03.15
* Time: 20:22
*/
@Command(name = "meta", description = "MetaGenerator. Generator for creating a new template set " +
"and configuration for Codegen. The output will be based on the language you " +
"specify, and includes default templates to include.")
public class Meta implements Runnable {
private static final Logger LOG = LoggerFactory.getLogger(Meta.class);
private static final String TEMPLATE_DIR_CLASSPATH = "codegen";
private static final String MUSTACHE_EXTENSION = ".mustache";
@Option(name = {"-o", "--output"}, title = "output directory",
description = "where to write the generated files (current dir by default)")
private String outputFolder = "";
@Option(name = {"-n", "--name"}, title = "name",
description = "the human-readable name of the generator")
private String name = "default";
@Option(name = {"-p", "--package"}, title = "package",
description = "the package to put the main class into (defaults to io.swagger.codegen)")
private String targetPackage = "io.swagger.codegen";
@Override
public void run() {
final File targetDir = new File(outputFolder);
LOG.info("writing to folder [{}]", targetDir.getAbsolutePath());
String mainClass = StringUtils.capitalize(name) + "Generator";
List<SupportingFile> supportingFiles = ImmutableList.of(
new SupportingFile("pom.mustache", "", "pom.xml"),
new SupportingFile("generatorClass.mustache",
on(File.separator).join("src/main/java", asPath(targetPackage)), mainClass.concat(".java")),
new SupportingFile("README.mustache", "", "README.md"),
new SupportingFile("api.template", "src/main/resources" + File.separator + name, "api.mustache"),
new SupportingFile("model.template", "src/main/resources" + File.separator + name, "model.mustache"),
new SupportingFile("services.mustache",
"src/main/resources/META-INF/services", "io.swagger.codegen.CodegenConfig")
);
Map<String, Object> data = new ImmutableMap.Builder<String, Object>()
.put("generatorPackage", targetPackage)
.put("generatorClass", mainClass)
.put("name", name)
.put("fullyQualifiedGeneratorClass", targetPackage + "." + mainClass).build();
with(supportingFiles).convert(processFiles(targetDir, data));
}
/**
* Converter method to process supporting files: execute with mustache,
* or simply copy to destination directory
* @param targetDir - destination directory
* @param data - map with additional params needed to process templates
* @return converter object to pass to lambdaj
*/
private Converter<SupportingFile, File> processFiles(final File targetDir, final Map<String, Object> data) {
return new Converter<SupportingFile, File>() {
private DefaultGenerator generator = new DefaultGenerator();
@Override
public File convert(SupportingFile support) {
try {
File destinationFolder = new File(new File(targetDir.getAbsolutePath()), support.folder);
File outputFile = new File(destinationFolder, support.destinationFilename);
String template = generator
.readTemplate(new File(TEMPLATE_DIR_CLASSPATH, support.templateFile).getPath());
String formatted = template;
if (support.templateFile.endsWith(MUSTACHE_EXTENSION)) {
LOG.info("writing file to {}", outputFile.getAbsolutePath());
formatted = Mustache.compiler().withLoader(loader(generator))
.defaultValue("")
.compile(template)
.execute(data);
} else {
LOG.info("copying file to {}", outputFile.getAbsolutePath());
}
FileUtils.writeStringToFile(outputFile, formatted);
return outputFile;
} catch (IOException e) {
throw new RuntimeException("Can't generate project", e);
}
}
};
}
/**
* Creates mustache loader for template using classpath loader
* @param generator - class with reader getter
* @return loader for template
*/
private Mustache.TemplateLoader loader(final DefaultGenerator generator) {
return new Mustache.TemplateLoader() {
public Reader getTemplate(String name) {
return generator.getTemplateReader(TEMPLATE_DIR_CLASSPATH
+ File.separator + name.concat(MUSTACHE_EXTENSION));
}
};
}
/**
* Converts package name to path on file system
* @param packageName - package name to convert
* @return relative path
*/
private String asPath(String packageName) {
return packageName.replace(".", File.separator);
}
}

View File

@ -0,0 +1,24 @@
io.swagger.codegen.languages.AndroidClientCodegen
io.swagger.codegen.languages.AsyncScalaClientCodegen
io.swagger.codegen.languages.CSharpClientCodegen
io.swagger.codegen.languages.JavaClientCodegen
io.swagger.codegen.languages.JaxRSServerCodegen
io.swagger.codegen.languages.NodeJSServerCodegen
io.swagger.codegen.languages.ObjcClientCodegen
io.swagger.codegen.languages.PerlClientCodegen
io.swagger.codegen.languages.PhpClientCodegen
io.swagger.codegen.languages.PythonClientCodegen
io.swagger.codegen.languages.Python3ClientCodegen
io.swagger.codegen.languages.Qt5CPPGenerator
io.swagger.codegen.languages.RetrofitClientCodegen
io.swagger.codegen.languages.RubyClientCodegen
io.swagger.codegen.languages.ScalaClientCodegen
io.swagger.codegen.languages.ScalatraServerCodegen
io.swagger.codegen.languages.SpringMVCServerCodegen
io.swagger.codegen.languages.StaticDocCodegen
io.swagger.codegen.languages.StaticHtmlGenerator
io.swagger.codegen.languages.SwaggerGenerator
io.swagger.codegen.languages.SwaggerYamlGenerator
io.swagger.codegen.languages.SwiftGenerator
io.swagger.codegen.languages.TizenClientCodegen
io.swagger.codegen.languages.AkkaScalaClientCodegen

View File

@ -0,0 +1,45 @@
/**
* Copyright 2015 Reverb, 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 io.swagger.generator;
import io.swagger.models.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
public class Bootstrap extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
ServletContext context = config.getServletContext();
DynamicSwaggerConfig bc = new DynamicSwaggerConfig();
bc.setBasePath("/api");
bc.setTitle("Swagger Generator");
bc.setDescription("This is an online swagger codegen server. You can find out more " +
"at <a href=\"https://github.com/wordnik/swagger-generator\">https://github.com/swagger-api/swagger-codegen</a> or on irc.freenode.net, #swagger." +
"http://helloreverb.com/terms/");
bc.setTermsOfServiceUrl("http://helloreverb.com/terms/");
bc.setContact("apiteam@swagger.io");
bc.setLicense("Apache 2.0");
bc.setVersion("1.0.0");
bc.setHost("generator.swagger.io");
bc.setLicenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html");
bc.setResourcePackage("io.swagger.generator.resource");
bc.setScan(true);
}
}

View File

@ -0,0 +1,69 @@
package io.swagger.generator;
import io.swagger.models.*;
import io.swagger.models.parameters.*;
import io.swagger.models.properties.*;
import io.swagger.codegen.*;
import io.swagger.util.Json;
import io.swagger.jaxrs.config.BeanConfig;
import java.util.*;
public class DynamicSwaggerConfig extends BeanConfig {
static List<String> clients = new ArrayList<String>();
static List<String> servers = new ArrayList<String>();
static {
List<CodegenConfig> extensions = Codegen.getExtensions();
for(CodegenConfig config : extensions) {
if(config.getTag().equals(CodegenType.CLIENT) || config.getTag().equals(CodegenType.DOCUMENTATION)) {
clients.add(config.getName());
}
else if(config.getTag().equals(CodegenType.SERVER)) {
servers.add(config.getName());
}
}
}
@Override
public Swagger configure(Swagger swagger) {
Path clientPath = swagger.getPaths().get("/gen/clients/{language}");
// update the path description based on what clients are available via SPI
if(clientPath != null) {
Operation post = clientPath.getPost();
Parameter framework = post.getParameters().get(0);
if(framework instanceof PathParameter) {
PathParameter param = (PathParameter) framework;
StringBuilder b = new StringBuilder();
for(String client : clients) {
if(b.toString().length() > 0)
b.append(", ");
b.append(client);
}
param.setDescription("available clients: " + b.toString());
}
}
Path serverPath = swagger.getPaths().get("/gen/servers/{framework}");
// update the path description based on what servers are available via SPI
if(serverPath != null) {
Operation post = serverPath.getPost();
Parameter framework = post.getParameters().get(0);
if(framework instanceof PathParameter) {
PathParameter param = (PathParameter) framework;
StringBuilder b = new StringBuilder();
for(String server : servers) {
if(b.toString().length() > 0)
b.append(", ");
b.append(server);
}
param.setDescription("available clients: " + b.toString());
}
}
return swagger.info(getInfo())
.host(getHost())
.basePath("/api");
}
}

View File

@ -0,0 +1,25 @@
/**
* Copyright 2015 Reverb, 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 io.swagger.generator.exception;
public class ApiException extends Exception{
private int code;
public ApiException (int code, String msg) {
super(msg);
this.code = code;
}
}

View File

@ -0,0 +1,25 @@
/**
* Copyright 2015 Reverb, 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 io.swagger.generator.exception;
public class BadRequestException extends ApiException {
private int code;
public BadRequestException (int code, String msg) {
super(code, msg);
this.code = code;
}
}

View File

@ -0,0 +1,25 @@
/**
* Copyright 2015 Reverb, 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 io.swagger.generator.exception;
public class NotFoundException extends ApiException {
private int code;
public NotFoundException (int code, String msg) {
super(code, msg);
this.code = code;
}
}

View File

@ -0,0 +1,84 @@
/**
* Copyright 2015 Reverb, 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 io.swagger.generator.model;
import javax.xml.bind.annotation.XmlTransient;
@javax.xml.bind.annotation.XmlRootElement
public class ApiResponse {
public static final int ERROR = 1;
public static final int WARNING = 2;
public static final int INFO = 3;
public static final int OK = 4;
public static final int TOO_BUSY = 5;
int code;
String type;
String message;
public ApiResponse(){}
public ApiResponse(int code, String message){
this.code = code;
switch(code){
case ERROR:
setType("error");
break;
case WARNING:
setType("warning");
break;
case INFO:
setType("info");
break;
case OK:
setType("ok");
break;
case TOO_BUSY:
setType("too busy");
break;
default:
setType("unknown");
break;
}
this.message = message;
}
@XmlTransient
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@ -0,0 +1,36 @@
/**
* Copyright 2015 Reverb, 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 io.swagger.generator.model;
public class Generated {
private String filename;
private String friendlyName;
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public String getFriendlyName() {
return friendlyName;
}
public void setFriendlyName(String friendlyName) {
this.friendlyName = friendlyName;
}
}

View File

@ -0,0 +1,44 @@
package io.swagger.generator.model;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.models.auth.SecuritySchemeDefinition;
import com.fasterxml.jackson.databind.*;
import java.util.*;
public class GeneratorInput {
private JsonNode spec;
private Map<String, String> options;
private String swaggerUrl;
private SecuritySchemeDefinition auth;
@ApiModelProperty(dataType="Object")
public JsonNode getSpec() {
return spec;
}
public void setSpec(JsonNode spec) {
this.spec = spec;
}
public Map<String, String> getOptions() {
return options;
}
public void setOptions(Map<String, String> options) {
this.options = options;
}
public String getSwaggerUrl() {
return swaggerUrl;
}
public void setSwaggerUrl(String url) {
this.swaggerUrl = url;
}
public SecuritySchemeDefinition getSecurityDefinition() {
return auth;
}
public void setSecurityDefinition(SecuritySchemeDefinition auth) {
this.auth = auth;
}
}

View File

@ -0,0 +1,65 @@
/**
* Copyright 2015 Reverb, 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 io.swagger.generator.model;
public class InputOption {
private String name;
private String description;
private Boolean required;
private String defaultValue;
public InputOption() {}
public InputOption(String name, String description, String defaultValue, Boolean required) {
this.name = name;
this.description = description;
this.defaultValue = defaultValue;
this.required = required;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setDescription(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public void setRequired(Boolean required) {
this.required = required;
}
public Boolean getRequired() {
return required;
}
public void setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
}
public String getDefaultValue() {
return defaultValue;
}
}

View File

@ -0,0 +1,26 @@
package io.swagger.generator.model;
public class ResponseCode {
private String code;
private String link;
public ResponseCode() {}
public ResponseCode(String code, String link) {
setCode(code);
setLink(link);
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
}

View File

@ -0,0 +1,167 @@
package io.swagger.generator.online;
import io.swagger.parser.SwaggerParser;
import io.swagger.generator.exception.*;
import io.swagger.codegen.*;
import io.swagger.models.Swagger;
import io.swagger.generator.model.*;
import io.swagger.util.Json;
import io.swagger.generator.util.ZipUtil;
import com.fasterxml.jackson.databind.JsonNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.List;
import java.util.ArrayList;
public class Generator {
static Logger LOGGER = LoggerFactory.getLogger(Generator.class);
public static String generateClient(String language, GeneratorInput opts) throws ApiException {
Swagger swagger;
LOGGER.debug("generate client for " + language);
if(opts == null) {
throw new BadRequestException(400, "No options were supplied");
}
JsonNode node = opts.getSpec();
if(node == null) {
if(opts.getSwaggerUrl() != null) {
swagger = new SwaggerParser().read(opts.getSwaggerUrl());
}
else
throw new BadRequestException(400, "No swagger specification was supplied");
}
else {
swagger = new SwaggerParser().read(node);
}
if(swagger == null) {
throw new BadRequestException(400, "The swagger specification supplied was not valid");
}
ClientOptInput clientOptInput = new ClientOptInput();
ClientOpts clientOpts = new ClientOpts();
String outputFolder = getTmpFolder().getAbsolutePath() + File.separator + language + "-client";
String outputFilename = outputFolder + "-bundle.zip";
clientOptInput
.opts(clientOpts)
.swagger(swagger);
CodegenConfig codegenConfig = Codegen.getConfig(language);
if(codegenConfig == null) {
throw new BadRequestException(400, "Unsupported target " + language + " supplied");
}
codegenConfig.setOutputDir(outputFolder);
Json.prettyPrint(clientOpts);
clientOptInput.setConfig(codegenConfig);
try{
List<File> files = new Codegen().opts(clientOptInput).generate();
if(files.size() > 0) {
List<File> filesToAdd = new ArrayList<File>();
System.out.println("adding to " + outputFolder);
filesToAdd.add(new File(outputFolder));
ZipUtil zip = new ZipUtil();
zip.compressFiles(filesToAdd, outputFilename);
}
else {
throw new BadRequestException(400, "A target generation was attempted, but no files were created!");
}
}
catch (Exception e) {
throw new BadRequestException(500, "Unable to build target: " + e.getMessage());
}
return outputFilename;
}
public static String generateServer(String language, GeneratorInput opts) throws ApiException {
LOGGER.debug("generate server for " + language);
Swagger swagger;
if(opts == null) {
throw new BadRequestException(400, "No options were supplied");
}
if(opts == null) {
throw new BadRequestException(400, "No options were supplied");
}
JsonNode node = opts.getSpec();
if(node == null) {
if(opts.getSwaggerUrl() != null) {
swagger = new SwaggerParser().read(opts.getSwaggerUrl());
}
else
throw new BadRequestException(400, "No swagger specification was supplied");
}
else {
swagger = new SwaggerParser().read(node);
}
if(swagger == null) {
throw new BadRequestException(400, "The swagger specification supplied was not valid");
}
ClientOptInput clientOptInput = new ClientOptInput();
ClientOpts clientOpts = new ClientOpts();
String outputFolder = getTmpFolder().getAbsolutePath() + File.separator + language + "-server";
String outputFilename = outputFolder + "-bundle.zip";
clientOptInput
.opts(clientOpts)
.swagger(swagger);
CodegenConfig codegenConfig = Codegen.getConfig(language);
if(codegenConfig == null) {
throw new BadRequestException(400, "Unsupported target " + language + " supplied");
}
codegenConfig.setOutputDir(outputFolder);
Json.prettyPrint(clientOpts);
clientOptInput.setConfig(codegenConfig);
try{
List<File> files = new Codegen().opts(clientOptInput).generate();
if(files.size() > 0) {
List<File> filesToAdd = new ArrayList<File>();
filesToAdd.add(new File(outputFolder));
ZipUtil zip = new ZipUtil();
zip.compressFiles(filesToAdd, outputFilename);
}
else {
throw new BadRequestException(400, "A target generation was attempted, but no files were created!");
}
}
catch (Exception e) {
throw new BadRequestException(500, "Unable to build target: " + e.getMessage());
}
return outputFilename;
}
public static InputOption clientOptions(String language) {
return null;
}
public static InputOption serverOptions(String language) {
return null;
}
protected static File getTmpFolder() {
try {
File outputFolder = File.createTempFile("codegen-", "-tmp");
outputFolder.delete();
outputFolder.mkdir();
outputFolder.deleteOnExit();
return outputFolder;
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

View File

@ -0,0 +1,50 @@
package io.swagger.generator.resource;
import io.swagger.generator.util.ValidationException;
import io.swagger.generator.exception.ApiException;
import io.swagger.generator.exception.BadRequestException;
import io.swagger.generator.exception.NotFoundException;
import io.swagger.generator.model.ApiResponse;
import javax.ws.rs.ext.*;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
@Provider
public class ExceptionWriter implements ExceptionMapper<Exception> {
public Response toResponse(Exception exception) {
if (exception instanceof javax.ws.rs.WebApplicationException) {
javax.ws.rs.WebApplicationException e = (javax.ws.rs.WebApplicationException) exception;
return Response
.status(e.getResponse().getStatus())
.entity(new ApiResponse(e.getResponse().getStatus(),
exception.getMessage())).build();
} else if (exception instanceof com.fasterxml.jackson.core.JsonParseException) {
return Response.status(400)
.entity(new ApiResponse(400, "bad input")).build();
} else if (exception instanceof ValidationException) {
ValidationException e = (ValidationException) exception;
return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
} else if (exception instanceof NotFoundException) {
return Response
.status(Status.NOT_FOUND)
.entity(new ApiResponse(ApiResponse.ERROR, exception
.getMessage())).build();
} else if (exception instanceof BadRequestException) {
return Response
.status(Status.BAD_REQUEST)
.entity(new ApiResponse(ApiResponse.ERROR, exception
.getMessage())).build();
} else if (exception instanceof ApiException) {
return Response
.status(Status.BAD_REQUEST)
.entity(new ApiResponse(ApiResponse.ERROR, exception
.getMessage())).build();
} else {
return Response.status(500)
.entity(new ApiResponse(500, "something bad happened"))
.build();
}
}
}

View File

@ -0,0 +1,138 @@
package io.swagger.generator.resource;
import io.swagger.codegen.*;
import io.swagger.generator.util.*;
import io.swagger.annotations.*;
import io.swagger.generator.model.*;
import io.swagger.generator.exception.BadRequestException;
import io.swagger.generator.online.Generator;
import java.io.File;
import java.util.*;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
@Path("/gen")
@Api(value = "/gen", description = "Resource for generating swagger components")
public class SwaggerResource {
private static Map<String, Generated> fileMap = new HashMap<String, Generated>();
static List<String> clients = new ArrayList<String>();
static List<String> servers = new ArrayList<String>();
static {
List<CodegenConfig> extensions = Codegen.getExtensions();
for(CodegenConfig config : extensions) {
if(config.getTag().equals(CodegenType.CLIENT) || config.getTag().equals(CodegenType.DOCUMENTATION)) {
clients.add(config.getName());
}
else if(config.getTag().equals(CodegenType.SERVER)) {
servers.add(config.getName());
}
}
}
@GET
@Path("/download/{fileId}")
@Produces({MediaType.APPLICATION_OCTET_STREAM})
@ApiOperation(value = "Downloads a pre-generated file",
response = String.class,
tags = {"clients", "servers"})
public Response downloadFile(@PathParam("fileId") String fileId) throws Exception {
Generated g = fileMap.get(fileId);
System.out.println("looking for fileId " + fileId);
System.out.println("got filename " + g.getFilename());
if(g.getFilename() != null) {
byte[] bytes = org.apache.commons.io.FileUtils.readFileToByteArray(new java.io.File(g.getFilename()));
return Response.ok(bytes, "application/zip")
.header("Content-Disposition","attachment; filename=\"" + g.getFriendlyName() + "-generated.zip\"")
.header("Accept-Range", "bytes")
.header("Content-Length", bytes.length)
.build();
}
else {
return Response.status(404).build();
}
}
@POST
@Path("/clients/{language}")
@ApiOperation(
value = "Generates a client library based on the config",
response = ResponseCode.class,
tags = "clients")
public Response generateClient(
@ApiParam(value = "The target language for the client library", allowableValues = "android,java,php,objc,docs", required = true) @PathParam("language") String language,
@ApiParam(value = "Configuration for building the client library", required = true) GeneratorInput opts) throws Exception {
String filename = Generator.generateClient(language, opts);
if(filename != null) {
String code = String.valueOf(System.currentTimeMillis());
Generated g = new Generated();
g.setFilename(filename);
g.setFriendlyName(language + "-client");
fileMap.put(code, g);
System.out.println(code + ", " + filename);
String link = "http://generator.swagger.io/api/gen/download/" + code;
return Response.ok().entity(new ResponseCode(code, link)).build();
}
else {
return Response.status(500).build();
}
}
@GET
@Path("/clients")
@ApiOperation(value = "Gets languages supported by the client generator",
response = String.class,
responseContainer = "List",
tags = "clients")
public Response clientOptions() {
String[] languages = new String[clients.size()];
languages = clients.toArray(languages);
return Response.ok().entity(languages).build();
}
@GET
@Path("/servers")
@ApiOperation(value = "Gets languages supported by the server generator",
response = String.class,
responseContainer = "List",
tags = "servers")
public Response serverOptions() {
String[] languages = new String[servers.size()];
languages = servers.toArray(languages);
return Response.ok().entity(languages).build();
}
@POST
@Path("/servers/{framework}")
@ApiOperation(value = "Generates a server library for the supplied server framework",
response = ResponseCode.class,
tags = "servers")
public Response generateServerForLanguage(
@ApiParam(value = "framework", allowableValues = "jaxrs,nodejs", required = true) @PathParam("framework") String framework,
@ApiParam(value = "parameters", required = true) GeneratorInput opts)
throws Exception {
if(framework == null)
throw new BadRequestException(400, "Framework is required");
String filename = Generator.generateServer(framework, opts);
System.out.println("generated name: " + filename);
if(filename != null) {
String code = String.valueOf(System.currentTimeMillis());
Generated g = new Generated();
g.setFilename(filename);
g.setFriendlyName(framework + "-server");
fileMap.put(code, g);
System.out.println(code + ", " + filename);
String link = "http://generator.swagger.io/api/gen/download/" + code;
return Response.ok().entity(new ResponseCode(code, link)).build();
}
else {
return Response.status(500).build();
}
}
}

View File

@ -0,0 +1,42 @@
/**
* Copyright 2015 Reverb, 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 io.swagger.generator.util;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
public class ApiOriginFilter implements javax.servlet.Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
res.addHeader("Access-Control-Allow-Headers", "Content-Type");
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}

View File

@ -0,0 +1,27 @@
package io.swagger.generator.util;
import java.util.List;
public class ValidationException extends Exception {
private int code;
private String msg;
private List<ValidationMessage> errors;
public ValidationException(String msg) {
super(msg);
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return msg;
}
public void setMessage(String msg) {
this.msg = msg;
}
}

View File

@ -0,0 +1,26 @@
package io.swagger.generator.util;
public class ValidationMessage {
private String path, message, severity;
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getSeverity() {
return severity;
}
public void setSeverity(String severity) {
this.severity = severity;
}
}

View File

@ -0,0 +1,124 @@
/**
* Copyright 2015 Reverb, 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 io.swagger.generator.util;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* This utility compresses a list of files to standard ZIP format file.
* It is able to compresses all sub files and sub directories, recursively.
* @author Ha Minh Nam
*
*/
public class ZipUtil {
/**
* A constants for buffer size used to read/write data
*/
private static final int BUFFER_SIZE = 4096;
/**
* Compresses a collection of files to a destination zip file
* @param listFiles A collection of files and directories
* @param destZipFile The path of the destination zip file
* @throws FileNotFoundException
* @throws IOException
*/
public void compressFiles(List<File> listFiles, String destZipFile) throws FileNotFoundException, IOException {
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(destZipFile));
for (File file : listFiles) {
if (file.isDirectory()) {
addFolderToZip(file, file.getName(), zos);
} else {
addFileToZip(file, zos);
}
}
zos.flush();
zos.close();
}
/**
* Adds a directory to the current zip output stream
* @param folder the directory to be added
* @param parentFolder the path of parent directory
* @param zos the current zip output stream
* @throws FileNotFoundException
* @throws IOException
*/
private void addFolderToZip(File folder, String parentFolder,
ZipOutputStream zos) throws FileNotFoundException, IOException {
for (File file : folder.listFiles()) {
if (file.isDirectory()) {
addFolderToZip(file, parentFolder + "/" + file.getName(), zos);
continue;
}
zos.putNextEntry(new ZipEntry(parentFolder + "/" + file.getName()));
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(file));
long bytesRead = 0;
byte[] bytesIn = new byte[BUFFER_SIZE];
int read = 0;
while ((read = bis.read(bytesIn)) != -1) {
zos.write(bytesIn, 0, read);
bytesRead += read;
}
zos.closeEntry();
}
}
/**
* Adds a file to the current zip output stream
* @param file the file to be added
* @param zos the current zip output stream
* @throws FileNotFoundException
* @throws IOException
*/
private void addFileToZip(File file, ZipOutputStream zos)
throws FileNotFoundException, IOException {
zos.putNextEntry(new ZipEntry(file.getName()));
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
file));
long bytesRead = 0;
byte[] bytesIn = new byte[BUFFER_SIZE];
int read = 0;
while ((read = bis.read(bytesIn)) != -1) {
zos.write(bytesIn, 0, read);
bytesRead += read;
}
zos.closeEntry();
}
}