/**
* Copyright (C) 2015 Zalando SE (http://tech.zalando.com)
*
* 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 org.zalando.stups.swagger.codegen;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ServiceLoader;
import com.google.common.collect.ImmutableMap;
import io.swagger.codegen.ClientOptInput;
import io.swagger.codegen.ClientOpts;
import io.swagger.codegen.CodegenConfig;
import io.swagger.codegen.DefaultGenerator;
import io.swagger.models.Model;
import io.swagger.models.Path;
import io.swagger.models.Swagger;
import io.swagger.parser.SwaggerParser;
/**
* Extracted from Mojo to reuse for easier template-testing.
*
* @author jbellmann
*/
public class StandaloneCodegenerator {
private Map<String, CodegenConfig> configs = new HashMap<String, CodegenConfig>();
private CodegeneratorLogger codeGeneratorLogger = new SystemOutCodegeneratorLogger();
private String apiFile;
private String language;
private File outputDirectory;
private String apiPackage;
private String modelPackage;
private boolean skipApigeneration;
private boolean skipModelgeneration;
private boolean enable303;
private boolean enableBuilderSupport;
private Map<String, Object> additionalProperties;
private List<String> excludedModels;
//
private boolean skipModelTests = true;
private boolean skipModelDocs = true;
private boolean skipApiTests = true;
private boolean skipApiDocs = true;
public static CodegeneratorBuilder builder() {
return new CodegeneratorBuilder();
}
public void generate() throws CodegenerationException {
if (!getOutputDirectory().exists()) {
getOutputDirectory().mkdirs();
}
checkModelPackage();
checkApiFileExist();
prepare();
//
final ClientOptInput clientOptInput = new ClientOptInput();
final ClientOpts clientOpts = new ClientOpts();
Swagger swagger = null;
getLog().info("Generate for language : " + language);
final CodegenConfig codegenConfig = getConfig(language);
if (codegenConfig == null) {
throw new CodegenerationException("No CodegenConfig-Implementation found for " + language);
}
codegenConfig.additionalProperties().putAll(additionalProperties);
if (codegenConfig instanceof ConfigurableCodegenConfig) {
// DefaultGenerator-line 72
if (skipApigeneration) {
((ConfigurableCodegenConfig) codegenConfig).skipApiGeneration();
}
if (skipModelgeneration) {
((ConfigurableCodegenConfig) codegenConfig).skipModelGeneration();
}
if (skipApigeneration && apiPackage == null) {
((ConfigurableCodegenConfig) codegenConfig).setApiPackage("");
} else {
// config
((ConfigurableCodegenConfig) codegenConfig).setApiPackage(apiPackage);
}
if (skipModelgeneration && modelPackage == null) {
((ConfigurableCodegenConfig) codegenConfig).setModelPackage("");
} else {
((ConfigurableCodegenConfig) codegenConfig).setModelPackage(modelPackage);
}
if (enable303) {
getLog().info("JSR 303 enabled ...");
if (((ConfigurableCodegenConfig) codegenConfig).is303Supported()) {
getLog().info("and supported by " + language);
((ConfigurableCodegenConfig) codegenConfig).enable303();
} else {
getLog().info("but not supported by " + language);
}
}
if (enableBuilderSupport) {
getLog().info("BuilderSupport enabled ...");
if (((ConfigurableCodegenConfig) codegenConfig).isBuilderSupported()) {
getLog().info("and supported by : " + language);
((ConfigurableCodegenConfig) codegenConfig).enableBuilderSupport();
} else {
getLog().info("but not supported by : " + language);
}
}
}
clientOptInput.setConfig(codegenConfig);
clientOptInput.getConfig().setOutputDir(outputDirectory.getAbsolutePath());
swagger = new SwaggerParser().read(this.apiFile, clientOptInput.getAuthorizationValues(), true);
if (skipApigeneration) {
getLog().info("API-GENERATION DISABLED ...");
System.setProperty("models", "");
swagger.setPaths(new HashMap<String, Path>(0));
}
if (skipModelgeneration) {
getLog().info("MODEL-GENERATION DISABLED ...");
System.setProperty("apis", "");
swagger.setDefinitions(new HashMap<String, Model>(0));
} else if (!excludedModels.isEmpty()) {
final Iterator<Entry<String, Model>> it = swagger.getDefinitions().entrySet().iterator();
while (it.hasNext()) {
final Map.Entry<String, Model> entry = it.next();
if (excludedModels.contains(entry.getKey())) {
getLog().info("REMOVE MODEL '" + entry.getKey() + "' FROM GENERATION ...");
it.remove();
}
}
}
if(skipModelTests){
System.setProperty("modelTests", Boolean.FALSE.toString());
}
if(skipModelDocs){
System.setProperty("modelDocs", Boolean.FALSE.toString());
}
if(skipApiTests){
System.setProperty("apiTests", Boolean.FALSE.toString());
}
if(skipApiDocs){
System.setProperty("apiDocs", Boolean.FALSE.toString());
}
try {
clientOptInput.opts(clientOpts).swagger(swagger);
final DefaultGenerator generator = (DefaultGenerator) new DefaultGenerator().opts(clientOptInput);
final List<File> generatedFiles = generator.generate();
getLog().info(generatedFiles.size() + " generated Files");
// updated to 2.1.4
// if (CodeGenStatus.FAILED.equals(generator.status)) {
// throw new CodegenerationException("Codegen failed by 'status'");
// }
} catch (final Exception e) {
throw new CodegenerationException(e.getMessage(), e);
}
}
public String getOutputDirectoryPath() {
return getOutputDirectory().getAbsolutePath();
}
private CodegeneratorLogger getLog() {
return codeGeneratorLogger;
}
protected void checkModelPackage() {
if (modelPackage == null || modelPackage.trim().isEmpty()) {
getLog().info("No 'modelPackage' was specified, use configured 'apiPackage' : " + apiPackage);
modelPackage = apiPackage;
}
}
protected void checkApiFileExist() throws CodegenerationException {
try {
URL url = new URL(apiFile);
String prot = url.getProtocol();
if ((!"https".equals(prot)) || (!"http".equals(prot))) {
getLog().info("'apiFile' should use 'http' or 'https'");
}
return;
} catch (MalformedURLException e) {
getLog().info("'apiFile' seems not be an valid URL, check file exist");
final File file = new File(apiFile);
if (!file.exists()) {
getLog().info("The 'apiFile' does not exists at : " + apiFile);
throw new CodegenerationException("The 'apiFile' does not exists at : " + apiFile);
}
}
}
public File getOutputDirectory() {
return this.outputDirectory;
}
protected void prepare() {
final List<CodegenConfig> extensions = getExtensions();
final StringBuilder sb = new StringBuilder();
for (final CodegenConfig config : extensions) {
if (sb.toString().length() != 0) {
sb.append(", ");
}
sb.append(config.getName());
getLog().info("register config : '" + config.getName() + "' with class : " + config.getClass().getName());
configs.put(config.getName(), config);
// do not know
// configString = sb.toString();
}
}
private CodegenConfig getConfig(final String name) {
if (configs.containsKey(name)) {
return configs.get(name);
} else {
try {
getLog().info("loading class " + name);
final Class<?> customClass = Class.forName(name);
getLog().info("loaded " + name);
return (CodegenConfig) customClass.newInstance();
} catch (final Exception e) {
throw new RuntimeException("can't load config-class for '" + name + "'", e);
}
}
}
private List<CodegenConfig> getExtensions() {
final ServiceLoader<CodegenConfig> loader = ServiceLoader.load(CodegenConfig.class);
final List<CodegenConfig> output = new ArrayList<CodegenConfig>();
final Iterator<CodegenConfig> itr = loader.iterator();
while (itr.hasNext()) {
output.add(itr.next());
}
return output;
}
public static class CodegeneratorBuilder {
private CodegeneratorLogger codeGeneratorLogger;
private String apiFile;
private String language;
private File outputDirectory;
private String apiPackage;
private String modelPackage;
private boolean skipModelgeneration = false;
private boolean skipApigeneration = false;
private boolean enable303 = false;
private boolean enableBuilderSupport = false;
private List<String> excludedModels = new ArrayList<String>(0);
private Map<String, Object> additionalProperties = ImmutableMap.of();
public CodegeneratorBuilder withApiFilePath(final String pathToApiFile) {
this.apiFile = pathToApiFile;
return this;
}
public CodegeneratorBuilder withApiFile(final File apiFile) {
this.apiFile = apiFile.getAbsolutePath();
return this;
}
public CodegeneratorBuilder forLanguage(final String languageDelimiter) {
this.language = languageDelimiter;
return this;
}
public CodegeneratorBuilder writeResultsTo(final File outputDirectory) {
this.outputDirectory = outputDirectory;
return this;
}
public CodegeneratorBuilder withApiPackage(final String apiPackage) {
this.apiPackage = apiPackage;
return this;
}
public CodegeneratorBuilder withModelPackage(final String modelPackage) {
this.modelPackage = modelPackage;
return this;
}
public CodegeneratorBuilder withLogger(final CodegeneratorLogger codegeneratorLogger) {
this.codeGeneratorLogger = codegeneratorLogger;
return this;
}
public CodegeneratorBuilder skipModelgeneration(final boolean skip) {
this.skipModelgeneration = skip;
return this;
}
public CodegeneratorBuilder withModelsExcluded(final List<String> excludedModels) {
this.excludedModels = excludedModels;
return this;
}
public CodegeneratorBuilder skipApigeneration(final boolean skip) {
this.skipApigeneration = skip;
return this;
}
public CodegeneratorBuilder enable303(final boolean enable303) {
this.enable303 = enable303;
return this;
}
public CodegeneratorBuilder enableBuilderSupport(final boolean enableBuilderSupport) {
this.enableBuilderSupport = enableBuilderSupport;
return this;
}
public CodegeneratorBuilder additionalProperties(Map<String, Object> properties) {
this.additionalProperties = properties;
return this;
}
public StandaloneCodegenerator build() {
final StandaloneCodegenerator generator = new StandaloneCodegenerator();
generator.apiFile = this.apiFile;
generator.language = this.language;
generator.outputDirectory = this.outputDirectory;
generator.apiPackage = this.apiPackage;
generator.modelPackage = this.modelPackage;
generator.skipModelgeneration = this.skipModelgeneration;
generator.excludedModels = this.excludedModels;
generator.skipApigeneration = this.skipApigeneration;
generator.enable303 = this.enable303;
generator.enableBuilderSupport = this.enableBuilderSupport;
generator.additionalProperties = this.additionalProperties;
if (this.codeGeneratorLogger != null) {
generator.codeGeneratorLogger = this.codeGeneratorLogger;
}
return generator;
}
}
}