diff --git a/modules/swagger-codegen-distribution/pom.xml b/modules/swagger-codegen-distribution/pom.xml new file mode 100644 index 00000000000..a70a79c27e1 --- /dev/null +++ b/modules/swagger-codegen-distribution/pom.xml @@ -0,0 +1,63 @@ + + + com.wordnik + swagger-codegen-project + 2.1.0-SNAPSHOT + ../.. + + 4.0.0 + com.wordnik + swagger-codegen-distribution + jar + swagger-codegen-distribution + 2.1.0-SNAPSHOT + + src/test/scala + target/classes + target/test-classes + install + target + ${project.artifactId}-${project.version} + + + + org.apache.maven.plugins + maven-shade-plugin + 2.3 + + + package + + shade + + + false + true + + ${java.io.tmpdir}/dependency-reduced-pom.xml + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + com.wordnik.swagger.codegen.Codegen + + + + + + + + + com.wordnik + swagger-codegen + ${project.parent.version} + + + \ No newline at end of file diff --git a/modules/swagger-codegen/pom.xml b/modules/swagger-codegen/pom.xml new file mode 100644 index 00000000000..8f0de9f7ddb --- /dev/null +++ b/modules/swagger-codegen/pom.xml @@ -0,0 +1,391 @@ + + + com.wordnik + swagger-codegen-project + 2.1.0-SNAPSHOT + ../.. + + 4.0.0 + com.wordnik + swagger-codegen + jar + swagger-codegen + 2.1.0-SNAPSHOT + + src/main/java + install + + + org.jvnet.wagon-svn + wagon-svn + 1.8 + + + org.apache.maven.wagon + wagon-ssh-external + 1.0-alpha-6 + + + org.apache.maven.wagon + wagon-webdav + 1.0-beta-1 + + + target + ${project.artifactId}-${project.version} + + + org.codehaus.mojo + exec-maven-plugin + 1.3.2 + + + + java + + + + + com.wordnik.swagger.codegen.Codegen + + + + org.apache.maven.plugins + maven-jar-plugin + + + + true + com.wordnik.swagger.codegen.Codegen + + + + + + maven-dependency-plugin + + + package + + copy-dependencies + + + ${project.build.directory}/lib + + + + + + net.alchim31.maven + scala-maven-plugin + + + + add-source + compile + testCompile + + + + + + incremental + + + -Xmx384m + + + -target:jvm-1.6 + -deprecation + + + + run-scalatest + org.scalatest.tools.Runner + + -p + ${project.build.testOutputDirectory} + + + -Xmx512m + + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.1.2 + + + attach-sources + verify + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.7 + + true + 1.6 + UTF-8 + 1g + + http://java.sun.com/javase/6/docs/api/ + + ${javadoc.package.exclude} + + + + attach-javadocs + verify + + jar + + + + + + maven-compiler-plugin + 3.0 + + 1.6 + 1.6 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + development + ${project.url} + ${project.version} + com.wordnik + + + + + + org.apache.maven.plugins + maven-site-plugin + 2.1 + + + org.apache.maven.plugins + maven-release-plugin + 2.1 + + + + + + net.alchim31.maven + scala-maven-plugin + ${scala-maven-plugin-version} + + + org.apache.maven.plugins + maven-gpg-plugin + + release + sign + + + + + + + + release-profile + + true + + + + + net.alchim31.maven + scala-maven-plugin + + + + compile + testCompile + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-source + prepare-package + + add-source + + + + src/main/scala + + + + + + + + + + release-sign-artifacts + + + performRelease + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + + + sign-artifacts + verify + + sign + + + + + + + + + + target/site + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9 + + true + true + + http://java.sun.com/javaee/5/docs/api + http://java.sun.com/j2se/1.5.0/docs/api + + + + + + net.alchim31.maven + scala-maven-plugin + ${scala-maven-plugin-version} + + + org.apache.maven.plugins + maven-jxr-plugin + 2.3 + + true + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + 2.6 + + + + project-team + + + + + + + + + io.swagger + swagger-parser + ${swagger-parser-version} + + + io.swagger + swagger-legacy-spec-parser + ${swagger-parser-version} + + + ${project.groupId} + swagger-core + ${swagger-core-version} + + + com.samskivert + jmustache + ${jmustache-version} + + + commons-io + commons-io + ${commons-io-version} + + + org.apache.maven + maven-plugin-tools-api + 2.0 + + + org.apache.felix + maven-bundle-plugin + ${felix-version} + + + org.slf4j + slf4j-ext + ${slf4j-version} + + + org.slf4j + slf4j-api + ${slf4j-version} + + + commons-lang + commons-lang + ${commons-lang-version} + + + commons-cli + commons-cli + ${commons-cli-version} + + + org.scalatest + scalatest_2.11 + ${scala-test-version} + test + + + + + sonatype-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + true + + + + diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/ClientOptInput.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/ClientOptInput.java new file mode 100644 index 00000000000..cdfb1191b2f --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/ClientOptInput.java @@ -0,0 +1,59 @@ +/** + * Copyright 2014 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 com.wordnik.swagger.codegen; + +import com.wordnik.swagger.codegen.ClientOpts; + +import com.wordnik.swagger.models.Swagger; + +public class ClientOptInput { + private ClientOpts opts; + private Swagger swagger; + protected CodegenConfig config; + + public ClientOptInput swagger(Swagger swagger) { + this.setSwagger(swagger); + return this; + } + public ClientOptInput opts(ClientOpts opts) { + this.setOpts(opts); + return this; + } + + public CodegenConfig getConfig() { + return config; + } + public void setConfig(CodegenConfig config) { + this.config = config; + } + + public void setOpts(ClientOpts opts) { + this.opts = opts; + } + + public ClientOpts getOpts() { + return opts; + } + + public void setSwagger(Swagger swagger) { + this.swagger = swagger; + } + + public Swagger getSwagger() { + return swagger; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/ClientOpts.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/ClientOpts.java new file mode 100644 index 00000000000..b8d681cc307 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/ClientOpts.java @@ -0,0 +1,52 @@ +package com.wordnik.swagger.codegen; + +import com.wordnik.swagger.codegen.auth.*; + +import java.util.*; + +public class ClientOpts { + protected String uri; + protected String target; + protected AuthMethod auth; + protected Map properties = new HashMap(); + protected String outputDirectory; + + public String getUri() { + return uri; + } + public void setUri(String uri) { + this.uri = uri; + } + + public String getTarget() { + return target; + } + public void setTarget(String target) { + this.target = target; + } + + public Map getProperties() { + return properties; + } + public void setProperties(Map properties) { + this.properties = properties; + } + + public String getOutputDirectory() { + return outputDirectory; + } + public void setOutputDirectory(String outputDirectory) { + this.outputDirectory = outputDirectory; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("ClientOpts: {\n"); + sb.append(" uri: ").append(uri).append(","); + sb.append(" auth: ").append(auth).append(","); + sb.append(properties); + sb.append("}"); + return sb.toString(); + } +} diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/Codegen.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/Codegen.java new file mode 100644 index 00000000000..c9e39c7f2f3 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/Codegen.java @@ -0,0 +1,123 @@ +package com.wordnik.swagger.codegen; + +import com.wordnik.swagger.codegen.languages.*; +import com.wordnik.swagger.models.Swagger; +import com.wordnik.swagger.util.*; + +import io.swagger.parser.SwaggerParser; + +import org.apache.commons.cli.*; + +import java.io.File; +import java.util.*; + +public class Codegen extends DefaultGenerator { + static String debugInfoOptions = "\nThe following additional debug options are available for all codegen targets:" + + "\n -DdebugSwagger prints the swagger specification as interpreted by the codegen" + + "\n -DdebugModels prints models passed to the template engine" + + "\n -DdebugOperations prints operations passed to the template engine" + + "\n -DdebugSupportingFiles prints additional data passed to the template engine"; + public static void main(String[] args) { + List extensions = getExtensions(); + Map configs = new HashMap(); + + StringBuilder sb = new StringBuilder(); + for(CodegenConfig config : extensions) { + if(sb.toString().length() != 0) + sb.append(", "); + sb.append(config.getName()); + configs.put(config.getName(), config); + } + + Options options = new Options(); + options.addOption("h", "help", false, "shows this message"); + options.addOption("l", "lang", true, "client language to generate.\nAvailable languages include:\n\t[" + sb.toString() + "]"); + options.addOption("o", "output", true, "where to write the generated files"); + options.addOption("i", "input-spec", true, "location of the swagger spec, as URL or file"); + options.addOption("t", "template-dir", true, "folder containing the template files"); + options.addOption("d", "debug-info", false, "prints additional info for debugging"); + + ClientOptInput clientOptInput = new ClientOptInput(); + ClientOpts clientOpts = new ClientOpts(); + Swagger swagger = null; + + CommandLine cmd = null; + try { + CommandLineParser parser = new BasicParser(); + CodegenConfig config = null; + + cmd = parser.parse(options, args); + if (cmd.hasOption("d")) { + usage(options); + System.out.println(debugInfoOptions); + return; + } + if (cmd.hasOption("l")) + clientOptInput.setConfig(getConfig(cmd.getOptionValue("l"), configs)); + if (cmd.hasOption("o")) + clientOptInput.getConfig().setOutputDir(cmd.getOptionValue("o")); + if (cmd.hasOption("h")) { + if(cmd.hasOption("l")) { + config = getConfig(String.valueOf(cmd.getOptionValue("l")), configs); + if(config != null) { + options.addOption("h", "help", true, config.getHelp()); + usage(options); + return; + } + } + usage(options); + return; + } + if (cmd.hasOption("i")) + swagger = new SwaggerParser().read(cmd.getOptionValue("i")); + if (cmd.hasOption("t")) + clientOpts.getProperties().put("templateDir", String.valueOf(cmd.getOptionValue("t"))); + } + catch (Exception e) { + usage(options); + return; + } + try{ + clientOptInput + .opts(clientOpts) + .swagger(swagger); + new Codegen().opts(clientOptInput).generate(); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public static List getExtensions() { + ServiceLoader loader = ServiceLoader.load(CodegenConfig.class); + List output = new ArrayList(); + Iterator itr = loader.iterator(); + while(itr.hasNext()) { + output.add(itr.next()); + } + return output; + } + + static void usage(Options options) { + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp( "Codegen", options ); + } + + static CodegenConfig getConfig(String name, Map configs) { + if(configs.containsKey(name)) { + return configs.get(name); + } + else { + // see if it's a class + try { + System.out.println("loading class " + name); + Class customClass = Class.forName(name); + System.out.println("loaded"); + return (CodegenConfig)customClass.newInstance(); + } + catch (Exception e) { + throw new RuntimeException("can't load class " + name); + } + } + } +} diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenConfig.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenConfig.java new file mode 100644 index 00000000000..73abe291c1d --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenConfig.java @@ -0,0 +1,51 @@ +package com.wordnik.swagger.codegen; + +import com.wordnik.swagger.models.*; +import com.wordnik.swagger.models.properties.*; + +import java.util.*; + +public interface CodegenConfig { + String getName(); + String getHelp(); + Map additionalProperties(); + String apiPackage(); + String apiFileFolder(); + String fileSuffix(); + String outputFolder(); + String templateDir(); + String modelFileFolder(); + String modelPackage(); + String toApiName(String name); + String toModelName(String name); + String toParamName(String name); + String escapeReservedWord(String name); + String getTypeDeclaration(Property p); + String getTypeDeclaration(String name); + void processOpts(); + + Set reservedWords(); + + List supportingFiles(); + + void setOutputDir(String dir); + String getOutputDir(); + + CodegenModel fromModel(String name, Model model); + CodegenOperation fromOperation(String resourcePath, String httpMethod, Operation operation); + Set defaultIncludes(); + Map typeMapping(); + Map instantiationTypes(); + Map importMapping(); + Map apiTemplateFiles(); + Map modelTemplateFiles(); + void processSwagger(Swagger swagger); + + String toApiFilename(String name); + String toModelFilename(String name); + String toModelImport(String name); + String toApiImport(String name); + void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map> operations); + Map postProcessModels(Map objs); + Map postProcessOperations(Map objs); +} diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenModel.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenModel.java new file mode 100644 index 00000000000..169886da22e --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenModel.java @@ -0,0 +1,16 @@ +package com.wordnik.swagger.codegen; + +import com.wordnik.swagger.models.*; +import com.wordnik.swagger.models.properties.*; + +import java.util.*; + +public class CodegenModel { + public String parent; + public String name, classname, description, classVarName, modelJson; + public String defaultValue; + public List vars = new ArrayList(); + public Set imports = new HashSet(); + public Boolean hasVars, emptyVars, hasMoreModels; + public ExternalDocs externalDocs; +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenModelFactory.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenModelFactory.java new file mode 100644 index 00000000000..b369623f37c --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenModelFactory.java @@ -0,0 +1,38 @@ +package com.wordnik.swagger.codegen; + +import java.util.HashMap; +import java.util.Map; + +public final class CodegenModelFactory { + + private static final Map> typeMapping = new HashMap>(); + + /** + * Configure a different implementation class. + * @param type the type that shall be replaced + * @param implementation the implementation class must extend the default class and must provide a public no-arg constructor + */ + public static void setTypeMapping(CodegenModelType type, Class implementation) { + if (!type.getDefaultImplementation().isAssignableFrom(implementation)) { + throw new IllegalArgumentException(implementation.getSimpleName() + " doesn't extend " + type.getDefaultImplementation().getSimpleName()); + } + try { + implementation.newInstance(); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + typeMapping.put(type, implementation); + } + + @SuppressWarnings("unchecked") + public static T newInstance(CodegenModelType type) { + Class classType = typeMapping.get(type); + try { + return (T) (classType != null ? classType : type.getDefaultImplementation()).newInstance(); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } +} diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenModelType.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenModelType.java new file mode 100644 index 00000000000..41c877532f0 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenModelType.java @@ -0,0 +1,20 @@ +package com.wordnik.swagger.codegen; + +public enum CodegenModelType { + + MODEL(CodegenModel.class), + OPERATION(CodegenOperation.class), + PARAMETER(CodegenParameter.class), + PROPERTY(CodegenProperty.class), + RESPONSE(CodegenResponse.class); + + private final Class defaultImplementation; + + private CodegenModelType(Class defaultImplementation) { + this.defaultImplementation = defaultImplementation; + } + + public Class getDefaultImplementation() { + return defaultImplementation; + } +} diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenOperation.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenOperation.java new file mode 100644 index 00000000000..3609e53d9ee --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenOperation.java @@ -0,0 +1,29 @@ +package com.wordnik.swagger.codegen; + +import com.wordnik.swagger.models.*; + +import java.util.*; + +public class CodegenOperation { + public Boolean hasConsumes, hasProduces, hasParams, returnTypeIsPrimitive, returnSimpleType, subresourceOperation; + public String path, operationId, returnType, httpMethod, returnBaseType, + returnContainer, summary, notes, baseName, defaultResponse; + + public List> consumes, produces; + public CodegenParameter bodyParam; + public List allParams = new ArrayList(); + public List bodyParams = new ArrayList(); + public List pathParams = new ArrayList(); + public List queryParams = new ArrayList(); + public List headerParams = new ArrayList(); + public List formParams = new ArrayList(); + public List tags; + public List responses = new ArrayList(); + public final List responseHeaders = new ArrayList(); + public Set imports = new HashSet(); + public List> examples; + public ExternalDocs externalDocs; + + // legacy support + public String nickname; +} diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenParameter.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenParameter.java new file mode 100644 index 00000000000..4480c172c32 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenParameter.java @@ -0,0 +1,37 @@ +package com.wordnik.swagger.codegen; + +public class CodegenParameter { + public Boolean isFormParam, isQueryParam, isPathParam, isHeaderParam, + isCookieParam, isBodyParam, isFile, notFile, hasMore, isContainer, secondaryParam; + public String baseName, paramName, dataType, collectionFormat, description, baseType; + /** + * Determines whether this parameter is mandatory. If the parameter is in "path", + * this property is required and its value MUST be true. Otherwise, the property + * MAY be included and its default value is false. + */ + public Boolean required; + + public CodegenParameter copy() { + CodegenParameter output = new CodegenParameter(); + output.isFile = this.isFile; + output.notFile = this.notFile; + output.hasMore = this.hasMore; + output.isContainer = this.isContainer; + output.secondaryParam = this.secondaryParam; + output.baseName = this.baseName; + output.paramName = this.paramName; + output.dataType = this.dataType; + output.collectionFormat = this.collectionFormat; + output.description = this.description; + output.baseType = this.baseType; + output.isFormParam = this.isFormParam; + output.isQueryParam = this.isQueryParam; + output.isPathParam = this.isPathParam; + output.isHeaderParam = this.isHeaderParam; + output.isCookieParam = this.isCookieParam; + output.isBodyParam = this.isBodyParam; + output.required = this.required; + + return output; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenProperty.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenProperty.java new file mode 100644 index 00000000000..cda9ab714d4 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenProperty.java @@ -0,0 +1,24 @@ +package com.wordnik.swagger.codegen; + +import java.util.*; + +public class CodegenProperty { + public String baseName, complexType, getter, setter, description, datatype, + name, min, max, defaultValue, baseType, containerType; + + /** maxLength validation for strings, see http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.1 */ + public Integer maxLength; + /** minLength validation for strings, see http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.2 */ + public Integer minLength; + /** pattern validation for strings, see http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.3 */ + public String pattern; + /** A free-form property to include an example of an instance for this schema. */ + public String example; + + public Double minimum, maximum, exclusiveMinimum, exclusiveMaximum; + public Boolean hasMore = null, required = null, secondaryParam = null; + public Boolean isPrimitiveType, isContainer, isNotContainer; + public boolean isEnum; + public List _enum; + public Map allowableValues; +} diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenResponse.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenResponse.java new file mode 100644 index 00000000000..92b908759b1 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenResponse.java @@ -0,0 +1,10 @@ +package com.wordnik.swagger.codegen; + +import java.util.*; + +public class CodegenResponse { + public String code, message; + public Boolean hasMore; + public List> examples; + Object schema; +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/DefaultCodegen.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/DefaultCodegen.java new file mode 100644 index 00000000000..e89b0f0b26f --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/DefaultCodegen.java @@ -0,0 +1,883 @@ +package com.wordnik.swagger.codegen; + +import com.wordnik.swagger.models.*; +import com.wordnik.swagger.models.parameters.*; +import com.wordnik.swagger.models.properties.*; +import com.wordnik.swagger.util.Json; + +import org.apache.commons.lang.StringUtils; + +import java.util.*; + +public class DefaultCodegen { + protected String outputFolder = ""; + protected Set defaultIncludes = new HashSet(); + protected Map typeMapping = new HashMap(); + protected Map instantiationTypes = new HashMap(); + protected Set reservedWords = new HashSet(); + protected Set languageSpecificPrimitives = new HashSet(); + protected Map importMapping = new HashMap(); + protected String modelPackage = "", apiPackage = "", fileSuffix; + protected Map apiTemplateFiles = new HashMap(); + protected Map modelTemplateFiles = new HashMap(); + protected String templateDir; + protected Map additionalProperties = new HashMap(); + protected List supportingFiles = new ArrayList(); + + public void processOpts(){ + if(additionalProperties.containsKey("templateDir")) { + this.setTemplateDir((String)additionalProperties.get("templateDir")); + } + } + + // override with any special post-processing + public Map postProcessModels(Map objs) { + return objs; + } + + // override with any special post-processing + public Map postProcessOperations(Map objs) { + return objs; + } + + // override with any special handling of the entire swagger spec + public void processSwagger(Swagger swagger) {} + + // override with any special text escaping logic + public String escapeText(String input) { + if(input != null) { + String output = input.replaceAll("\n", " "); + output = output.replace("\"", "\\\""); + return output; + } + return input; + } + + public Set defaultIncludes() { + return defaultIncludes; + } + public Map typeMapping() { + return typeMapping; + } + public Map instantiationTypes() { + return instantiationTypes; + } + public Set reservedWords() { + return reservedWords; + } + public Set languageSpecificPrimitives() { + return languageSpecificPrimitives; + } + public Map importMapping() { + return importMapping; + } + public String modelPackage() { + return modelPackage; + } + public String apiPackage() { + return apiPackage; + } + public String fileSuffix() { + return fileSuffix; + } + public String templateDir() { + return templateDir; + } + public Map apiTemplateFiles() { + return apiTemplateFiles; + } + public Map modelTemplateFiles() { + return modelTemplateFiles; + } + + public String apiFileFolder() { + return outputFolder + "/" + apiPackage().replaceAll("\\.", "/"); + } + + public String modelFileFolder() { + return outputFolder + "/" + modelPackage().replaceAll("\\.", "/"); + } + + public Map additionalProperties() { + return additionalProperties; + } + public List supportingFiles() { + return supportingFiles; + } + public String outputFolder() { + return outputFolder; + } + + public void setOutputDir(String dir) { + this.outputFolder = dir; + } + public String getOutputDir() { + return outputFolder(); + } + + public void setTemplateDir(String templateDir) { + this.templateDir = templateDir; + } + + public String toApiFilename(String name) { + return initialCaps(name) + "Api"; + } + + public String toModelFilename(String name) { + return name; + } + + public String toVarName(String name) { + if(reservedWords.contains(name)) + return escapeReservedWord(name); + else + return name; + } + + public String toParamName(String name) { + if(reservedWords.contains(name)) { + return escapeReservedWord(name); + } + return name; + } + + public String escapeReservedWord(String name) { + throw new RuntimeException("reserved word " + name + " not allowed"); + } + + public String toModelImport(String name) { + if("".equals(modelPackage())) + return name; + else + return modelPackage() + "." + name; + } + + public String toApiImport(String name) { + return apiPackage() + "." + name; + } + + public DefaultCodegen() { + defaultIncludes = new HashSet( + Arrays.asList("double", + "int", + "long", + "short", + "char", + "float", + "String", + "boolean", + "Boolean", + "Double", + "Void", + "Integer", + "Long", + "Float") + ); + + typeMapping = new HashMap(); + typeMapping.put("array", "List"); + typeMapping.put("map", "Map"); + typeMapping.put("List", "List"); + typeMapping.put("boolean", "Boolean"); + typeMapping.put("string", "String"); + typeMapping.put("int", "Integer"); + typeMapping.put("float", "Float"); + typeMapping.put("number", "BigDecimal"); + typeMapping.put("DateTime", "Date"); + typeMapping.put("long", "Long"); + typeMapping.put("short", "Short"); + typeMapping.put("char", "String"); + typeMapping.put("double", "Double"); + typeMapping.put("object", "Object"); + typeMapping.put("integer", "Integer"); + + instantiationTypes = new HashMap(); + + reservedWords = new HashSet(); + + importMapping = new HashMap(); + importMapping.put("BigDecimal", "java.math.BigDecimal"); + importMapping.put("UUID", "java.util.UUID"); + importMapping.put("File", "java.io.File"); + importMapping.put("Date", "java.util.Date"); + importMapping.put("Timestamp", "java.sql.Timestamp"); + importMapping.put("Map", "java.util.Map"); + importMapping.put("HashMap", "java.util.HashMap"); + importMapping.put("Array", "java.util.List"); + importMapping.put("ArrayList", "java.util.ArrayList"); + importMapping.put("List", "java.util.*"); + importMapping.put("Set", "java.util.*"); + importMapping.put("DateTime", "org.joda.time.*"); + importMapping.put("LocalDateTime", "org.joda.time.*"); + importMapping.put("LocalDate", "org.joda.time.*"); + importMapping.put("LocalTime", "org.joda.time.*"); + } + + public String toInstantiationType(Property p) { + if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + String inner = getSwaggerType(ap.getAdditionalProperties()); + return instantiationTypes.get("map") + ""; + } + else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + return instantiationTypes.get("array") + "<" + inner + ">"; + } + else + return null; + } + + public String toDefaultValue(Property p) { + if(p instanceof StringProperty) + return "null"; + else if (p instanceof BooleanProperty) + return "null"; + else if(p instanceof DateProperty) + return "null"; + else if(p instanceof DateTimeProperty) + return "null"; + else if (p instanceof DoubleProperty) + return "null"; + else if (p instanceof FloatProperty) + return "null"; + else if (p instanceof IntegerProperty) + return "null"; + else if (p instanceof LongProperty) + return "null"; + else if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + String inner = getSwaggerType(ap.getAdditionalProperties()); + return "new HashMap() "; + } + else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + return "new ArrayList<" + inner + ">() "; + } + else + return "null"; + } + + /** + * returns the swagger type for the property + **/ + public String getSwaggerType(Property p) { + String datatype = null; + if(p instanceof StringProperty) + datatype = "string"; + else if (p instanceof BooleanProperty) + datatype = "boolean"; + else if(p instanceof DateProperty) + datatype = "date"; + else if(p instanceof DateTimeProperty) + datatype = "DateTime"; + else if (p instanceof DoubleProperty) + datatype = "double"; + else if (p instanceof FloatProperty) + datatype = "float"; + else if (p instanceof IntegerProperty) + datatype = "integer"; + else if (p instanceof LongProperty) + datatype = "long"; + else if (p instanceof MapProperty) + datatype = "map"; + else if (p instanceof DecimalProperty) + datatype = "number"; + else if (p instanceof RefProperty) { + RefProperty r = (RefProperty)p; + datatype = r.get$ref(); + if(datatype.indexOf("#/definitions/") == 0) + datatype = datatype.substring("#/definitions/".length()); + } + else { + if(p != null) datatype = p.getType(); + } + return datatype; + } + + public String initialCaps(String name) { + return Character.toUpperCase(name.charAt(0)) + name.substring(1); + } + + public String getTypeDeclaration(String name) { + return name; + } + + public String getTypeDeclaration(Property p) { + String swaggerType = getSwaggerType(p); + if(typeMapping.containsKey(swaggerType)) + return typeMapping.get(swaggerType); + return swaggerType; + } + + public String toApiName(String name) { + if(name.length() == 0) + return "DefaultApi"; + return initialCaps(name) + "Api"; + } + + public String toModelName(String name) { + return initialCaps(name); + } + + public CodegenModel fromModel(String name, Model model) { + CodegenModel m = CodegenModelFactory.newInstance(CodegenModelType.MODEL); + if(reservedWords.contains(name)) + m.name = escapeReservedWord(name); + else + m.name = name; + m.description = model.getDescription(); + m.classname = toModelName(name); + m.classVarName = toVarName(name); + m.modelJson = Json.pretty(model); + m.externalDocs = model.getExternalDocs(); + int count = 0; + if(model instanceof ArrayModel) { + ArrayModel am = (ArrayModel) model; + ArrayProperty arrayProperty = new ArrayProperty(am.getItems()); + CodegenProperty cp = fromProperty(name, arrayProperty); + if(cp.complexType != null && !defaultIncludes.contains(cp.complexType)) + m.imports.add(cp.complexType); + m.parent = toInstantiationType(arrayProperty); + String containerType = cp.containerType; + if(instantiationTypes.containsKey(containerType)) + m.imports.add(instantiationTypes.get(containerType)); + if(typeMapping.containsKey(containerType)) { + containerType = typeMapping.get(containerType); + cp.containerType = containerType; + m.imports.add(containerType); + } + } + else if (model instanceof RefModel) { + // TODO + } + else { + ModelImpl impl = (ModelImpl) model; + if(impl.getAdditionalProperties() != null) { + MapProperty mapProperty = new MapProperty(impl.getAdditionalProperties()); + CodegenProperty cp = fromProperty(name, mapProperty); + if(cp.complexType != null && !defaultIncludes.contains(cp.complexType)) + m.imports.add(cp.complexType); + m.parent = toInstantiationType(mapProperty); + String containerType = cp.containerType; + if(instantiationTypes.containsKey(containerType)) + m.imports.add(instantiationTypes.get(containerType)); + if(typeMapping.containsKey(containerType)) { + containerType = typeMapping.get(containerType); + cp.containerType = containerType; + m.imports.add(containerType); + } + } + if(impl.getProperties() != null && impl.getProperties().size() > 0) { + m.hasVars = true; + for(String key: impl.getProperties().keySet()) { + Property prop = impl.getProperties().get(key); + + if(prop == null) { + System.out.println("null property for " + key); + } + else { + CodegenProperty cp = fromProperty(key, prop); + cp.required = false; + if(impl.getRequired() != null) { + for(String req : impl.getRequired()) { + if(key.equals(req)) + cp.required = true; + } + } + if(cp.complexType != null && !defaultIncludes.contains(cp.complexType)) { + m.imports.add(cp.complexType); + } + m.vars.add(cp); + count += 1; + if(count != impl.getProperties().keySet().size()) + cp.hasMore = new Boolean(true); + if(cp.isContainer != null) { + String arrayImport = typeMapping.get("array"); + if(arrayImport != null && + !languageSpecificPrimitives.contains(arrayImport) && + !defaultIncludes.contains(arrayImport)) + m.imports.add(arrayImport); + } + + if(cp.complexType != null && + !languageSpecificPrimitives.contains(cp.complexType) && + !defaultIncludes.contains(cp.complexType)) + m.imports.add(cp.complexType); + + if(cp.baseType != null && + !languageSpecificPrimitives.contains(cp.baseType) && + !defaultIncludes.contains(cp.baseType)) + m.imports.add(cp.baseType); + } + } + } + else { + m.emptyVars = true; + } + } + return m; + } + + public CodegenProperty fromProperty(String name, Property p) { + if(p == null) { + System.out.println("unexpected missing property for name " + null); + return null; + } + CodegenProperty property = CodegenModelFactory.newInstance(CodegenModelType.PROPERTY); + + property.name = toVarName(name); + property.baseName = name; + property.description = escapeText(p.getDescription()); + property.getter = "get" + initialCaps(name); + property.setter = "set" + initialCaps(name); + property.example = p.getExample(); + property.defaultValue = toDefaultValue(p); + + String type = getSwaggerType(p); + + if(p instanceof AbstractNumericProperty) { + AbstractNumericProperty np = (AbstractNumericProperty) p; + property.minimum = np.getMinimum(); + property.maximum = np.getMaximum(); + property.exclusiveMinimum = np.getExclusiveMinimum(); + property.exclusiveMaximum = np.getExclusiveMaximum(); + + // legacy support + Map allowableValues = new HashMap(); + if(np.getMinimum() != null) + allowableValues.put("min", np.getMinimum()); + if(np.getMaximum() != null) + allowableValues.put("max", np.getMaximum()); + property.allowableValues = allowableValues; + } + + if(p instanceof StringProperty) { + StringProperty sp = (StringProperty) p; + property.maxLength = sp.getMaxLength(); + property.minLength = sp.getMinLength(); + property.pattern = sp.getPattern(); + if(sp.getEnum() != null) { + List _enum = sp.getEnum(); + property._enum = _enum; + property.isEnum = true; + + // legacy support + Map allowableValues = new HashMap(); + allowableValues.put("values", _enum); + property.allowableValues = allowableValues; + } + } + + property.datatype = property.isEnum + ? StringUtils.capitalize(property.name) + "Enum" + : getTypeDeclaration(p); + property.baseType = getSwaggerType(p); + + if(p instanceof ArrayProperty) { + property.isContainer = true; + property.containerType = "array"; + ArrayProperty ap = (ArrayProperty) p; + CodegenProperty cp = fromProperty("inner", ap.getItems()); + if(cp == null) { + System.out.println("skipping invalid property:"); + Json.prettyPrint(p); + } + else { + property.baseType = getSwaggerType(p); + if(!languageSpecificPrimitives.contains(cp.baseType)) + property.complexType = cp.baseType; + else + property.isPrimitiveType = true; + } + } + else if(p instanceof MapProperty) { + property.isContainer = true; + property.containerType = "map"; + MapProperty ap = (MapProperty) p; + CodegenProperty cp = fromProperty("inner", ap.getAdditionalProperties()); + + property.baseType = getSwaggerType(p); + if(!languageSpecificPrimitives.contains(cp.baseType)) + property.complexType = cp.baseType; + else + property.isPrimitiveType = true; + } + else { + property.isNotContainer = true; + if(languageSpecificPrimitives().contains(type)) + property.isPrimitiveType = true; + else + property.complexType = property.baseType; + } + return property; + } + + public CodegenOperation fromOperation(String path, String httpMethod, Operation operation){ + CodegenOperation op = CodegenModelFactory.newInstance(CodegenModelType.OPERATION); + Set imports = new HashSet(); + + String operationId = operation.getOperationId(); + if(operationId == null) { + String tmpPath = path; + tmpPath = tmpPath.replaceAll("\\{", ""); + tmpPath = tmpPath.replaceAll("\\}", ""); + String[] parts = (tmpPath + "/" + httpMethod).split("/"); + StringBuilder builder = new StringBuilder(); + if("/".equals(tmpPath)) { + // must be root tmpPath + builder.append("root"); + } + for(int i = 0; i < parts.length; i++) { + String part = parts[i]; + if(part.length() > 0) { + if(builder.toString().length() == 0) + part = Character.toLowerCase(part.charAt(0)) + part.substring(1); + else + part = initialCaps(part); + builder.append(part); + } + } + operationId = builder.toString(); + System.out.println("generated operationId " + operationId); + } + op.path = path; + op.operationId = operationId; + op.summary = escapeText(operation.getSummary()); + op.notes = escapeText(operation.getDescription()); + op.tags = operation.getTags(); + + Response methodResponse = null; + + if(operation.getConsumes() != null && operation.getConsumes().size() > 0) { + List> c = new ArrayList>(); + int count = 0; + for(String key: operation.getConsumes()) { + Map mediaType = new HashMap(); + mediaType.put("mediaType", key); + count += 1; + if (count < operation.getConsumes().size()) + mediaType.put("hasMore", "true"); + c.add(mediaType); + } + op.consumes = c; + op.hasConsumes = true; + } + + if(operation.getProduces() != null && operation.getProduces().size() > 0) { + List> c = new ArrayList>(); + int count = 0; + for(String key: operation.getProduces()) { + Map mediaType = new HashMap(); + mediaType.put("mediaType", key); + count += 1; + if (count < operation.getProduces().size()) + mediaType.put("hasMore", "true"); + c.add(mediaType); + } + op.produces = c; + op.hasProduces = true; + } + + if(operation.getResponses() != null) { + for(String responseCode: new TreeSet(operation.getResponses().keySet())) { + Response response = operation.getResponses().get(responseCode); + if (responseCode.startsWith("2")) { + // use the first, i.e. the smallest 2xx response status as methodResponse + methodResponse = response; + break; + } + } + if(methodResponse == null && operation.getResponses().keySet().contains("default")) { + methodResponse = operation.getResponses().get("default"); + } + for(String responseCode: operation.getResponses().keySet()) { + Response response = operation.getResponses().get(responseCode); + if(response != methodResponse) { + CodegenResponse r = fromResponse(responseCode, response); + op.responses.add(r); + } + for(int i = 0; i < op.responses.size() - 1; i++) { + CodegenResponse r = op.responses.get(i); + r.hasMore = new Boolean(true); + } + } + } + + if(methodResponse != null) { + if (methodResponse.getSchema() != null) { + CodegenProperty cm = fromProperty("response", methodResponse.getSchema()); + + Property responseProperty = methodResponse.getSchema(); + + if(responseProperty instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) responseProperty; + CodegenProperty innerProperty = fromProperty("response", ap.getItems()); + op.returnBaseType = innerProperty.baseType; + } + else { + if(cm.complexType != null) + op.returnBaseType = cm.complexType; + else + op.returnBaseType = cm.baseType; + } + op.examples = toExamples(methodResponse.getExamples()); + op.defaultResponse = toDefaultValue(responseProperty); + op.returnType = cm.datatype; + if(cm.isContainer != null) { + op.returnContainer = cm.complexType; + } + else + op.returnSimpleType = true; + if (languageSpecificPrimitives().contains(op.returnBaseType) || op.returnBaseType == null) + op.returnTypeIsPrimitive = true; + } + addHeaders(methodResponse, op.responseHeaders); + } + + if(op.returnBaseType == null) { + op.returnTypeIsPrimitive = true; + op.returnSimpleType = true; + } + + if(op.returnBaseType != null && + !defaultIncludes.contains(op.returnBaseType) && + !languageSpecificPrimitives.contains(op.returnBaseType)) + imports.add(op.returnBaseType); + + List parameters = operation.getParameters(); + CodegenParameter bodyParam = null; + List allParams = new ArrayList(); + List bodyParams = new ArrayList(); + List pathParams = new ArrayList(); + List queryParams = new ArrayList(); + List headerParams = new ArrayList(); + List cookieParams = new ArrayList(); + List formParams = new ArrayList(); + + if(parameters != null) { + for(Parameter param : parameters) { + CodegenParameter p = fromParameter(param, imports); + allParams.add(p); + if(param instanceof QueryParameter) { + p.isQueryParam = new Boolean(true); + queryParams.add(p.copy()); + } + else if(param instanceof PathParameter) { + p.required = true; + p.isPathParam = new Boolean(true); + pathParams.add(p.copy()); + } + else if(param instanceof HeaderParameter) { + p.isHeaderParam = new Boolean(true); + headerParams.add(p.copy()); + } + else if(param instanceof CookieParameter) { + p.isCookieParam = new Boolean(true); + cookieParams.add(p.copy()); + } + else if(param instanceof BodyParameter) { + p.isBodyParam = new Boolean(true); + bodyParam = p; + bodyParams.add(p.copy()); + } + else if(param instanceof FormParameter) { + if("file".equals(p.dataType)) + p.isFile = true; + else + p.notFile = true; + p.isFormParam = new Boolean(true); + formParams.add(p.copy()); + } + } + } + for(String i: imports) { + if(!defaultIncludes.contains(i) && !languageSpecificPrimitives.contains(i)){ + op.imports.add(i); + } + } + op.bodyParam = bodyParam; + op.httpMethod = httpMethod.toUpperCase(); + op.allParams = addHasMore(allParams); + op.bodyParams = addHasMore(bodyParams); + op.pathParams = addHasMore(pathParams); + op.queryParams = addHasMore(queryParams); + op.headerParams = addHasMore(headerParams); + // op.cookieParams = cookieParams; + op.formParams = addHasMore(formParams); + // legacy support + op.nickname = operationId; + + if(op.allParams.size() > 0) + op.hasParams = true; + op.externalDocs = operation.getExternalDocs(); + + return op; + } + + public CodegenResponse fromResponse(String responseCode, Response response) { + CodegenResponse r = CodegenModelFactory.newInstance(CodegenModelType.RESPONSE); + if("default".equals(responseCode)) + r.code = "0"; + else + r.code = responseCode; + r.message = response.getDescription(); + r.schema = response.getSchema(); + r.examples = toExamples(response.getExamples()); + return r; + } + + public CodegenParameter fromParameter(Parameter param, Set imports) { + CodegenParameter p = CodegenModelFactory.newInstance(CodegenModelType.PARAMETER); + p.baseName = param.getName(); + p.description = param.getDescription(); + p.required = param.getRequired(); + + if(param instanceof SerializableParameter) { + SerializableParameter qp = (SerializableParameter) param; + Property property = null; + String collectionFormat = null; + if("array".equals(qp.getType())) { + Property inner = qp.getItems(); + if(inner == null) { + System.out.println("warning! No inner type supplied for array parameter \"" + qp.getName() + "\", using String"); + inner = new StringProperty().description("//TODO automatically added by swagger-codegen"); + } + property = new ArrayProperty(inner); + collectionFormat = qp.getCollectionFormat(); + CodegenProperty pr = fromProperty("inner", inner); + p.baseType = pr.datatype; + imports.add(pr.baseType); + } + else + property = PropertyBuilder.build(qp.getType(), qp.getFormat(), null); + if(property == null) { + System.out.println("warning! Property type \"" + qp.getType() + "\" not found for parameter \"" + param.getName() + "\", using String"); + property = new StringProperty().description("//TODO automatically added by swagger-codegen. Type was " + qp.getType() + " but not supported"); + } + CodegenProperty model = fromProperty(qp.getName(), property); + p.collectionFormat = collectionFormat; + p.dataType = model.datatype; + p.paramName = toParamName(qp.getName()); + + if(model.complexType != null) { + imports.add(model.complexType); + } + } + else { + BodyParameter bp = (BodyParameter) param; + Model model = bp.getSchema(); + + if(model instanceof ModelImpl) { + ModelImpl impl = (ModelImpl) model; + CodegenModel cm = fromModel(bp.getName(), impl); + if(cm.emptyVars != null && cm.emptyVars == false) { + p.dataType = getTypeDeclaration(cm.classname); + imports.add(p.dataType); + } + else { + // TODO: missing format, so this will not always work + Property prop = PropertyBuilder.build(impl.getType(), null, null); + CodegenProperty cp = fromProperty("property", prop); + if(cp != null) { + p.dataType = cp.datatype; + } + } + } + else if(model instanceof ArrayModel) { + // to use the built-in model parsing, we unwrap the ArrayModel + // and get a single property from it + ArrayModel impl = (ArrayModel) model; + CodegenModel cm = fromModel(bp.getName(), impl); + // get the single property + ArrayProperty ap = new ArrayProperty().items(impl.getItems()); + CodegenProperty cp = fromProperty("inner", ap); + if(cp.complexType != null) { + imports.add(cp.complexType); + } + imports.add(cp.baseType); + p.dataType = cp.datatype; + p.isContainer = true; + } + else{ + Model sub = bp.getSchema(); + if(sub instanceof RefModel) { + String name = ((RefModel)sub).getSimpleRef(); + if(typeMapping.containsKey(name)) + name = typeMapping.get(name); + else { + name = toModelName(name); + if(defaultIncludes.contains(name)) { + imports.add(name); + } + imports.add(name); + name = getTypeDeclaration(name); + } + p.dataType = name; + } + } + p.paramName = toParamName(bp.getName()); + } + return p; + } + + protected List> toExamples(Map examples) { + if(examples == null) + return null; + + List> output = new ArrayList>(); + for(String key: examples.keySet()) { + String value = examples.get(key); + + Map kv = new HashMap(); + kv.put("contentType", key); + kv.put("example", value); + output.add(kv); + } + return output; + } + + private void addHeaders(Response response, List target) { + if (response.getHeaders() != null) { + for (Map.Entry headers : response.getHeaders().entrySet()) { + target.add(fromProperty(headers.getKey(), headers.getValue())); + } + } + } + + private List addHasMore(List objs) { + if(objs != null) { + for(int i = 0; i < objs.size(); i++) { + if(i > 0) + objs.get(i).secondaryParam = new Boolean(true); + if(i < objs.size() - 1) + objs.get(i).hasMore = new Boolean(true); + } + } + return objs; + } + + private Map addHasMore(Map objs) { + if(objs != null) { + for(int i = 0; i < objs.size() - 1; i++) { + if(i > 0) + objs.put("secondaryParam", new Boolean(true)); + if(i < objs.size() - 1) + objs.put("hasMore", true); + } + } + return objs; + } + + + public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map> operations) { + List opList = operations.get(tag); + if(opList == null) { + opList = new ArrayList(); + operations.put(tag, opList); + } + opList.add(co); + co.baseName = tag; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/DefaultGenerator.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/DefaultGenerator.java new file mode 100644 index 00000000000..d852adfec83 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/DefaultGenerator.java @@ -0,0 +1,371 @@ +package com.wordnik.swagger.codegen; + +import com.wordnik.swagger.models.*; +import com.wordnik.swagger.util.*; +import com.samskivert.mustache.*; + +import org.apache.commons.io.FileUtils; + +import java.util.*; +import java.util.regex.*; +import java.io.*; + +public class DefaultGenerator implements Generator { + private CodegenConfig config; + private ClientOptInput opts = null; + private Swagger swagger = null; + + public Generator opts(ClientOptInput opts) { + this.opts = opts; + + this.swagger = opts.getSwagger(); + ClientOpts clientOpts = opts.getOpts(); + this.config = opts.getConfig(); + this.config.additionalProperties().putAll(clientOpts.getProperties()); + + return this; + } + + public void generate() { + if(swagger == null || config == null) { + throw new RuntimeException("missing swagger input or config!"); + } + if(System.getProperty("debugSwagger") != null) { + Json.prettyPrint(swagger); + } + try { + config.processOpts(); + if(swagger.getInfo() != null) { + Info info = swagger.getInfo(); + if(info.getTitle() != null) + config.additionalProperties().put("appName", info.getTitle()); + if(info.getDescription() != null) + config.additionalProperties().put("appDescription", info.getDescription()); + if(info.getContact() != null) { + Contact contact = info.getContact(); + config.additionalProperties().put("infoUrl", contact.getUrl()); + if(contact.getEmail() != null) + config.additionalProperties().put("infoEmail", contact.getEmail()); + } + if(info.getLicense() != null) { + License license = info.getLicense(); + if(license.getName() != null) + config.additionalProperties().put("licenseInfo", license.getName()); + if(license.getUrl() != null) + config.additionalProperties().put("licenseUrl", license.getUrl()); + } + } + + StringBuilder hostBuilder = new StringBuilder(); + if(swagger.getSchemes() != null && swagger.getSchemes().size() > 0) { + hostBuilder.append(swagger.getSchemes().get(0).toValue()); + hostBuilder.append("://"); + } + else + hostBuilder.append("https://"); + hostBuilder.append(swagger.getHost()).append(swagger.getBasePath()); + String basePath = hostBuilder.toString(); + + List allOperations = new ArrayList(); + List allModels = new ArrayList(); + + // models + Map definitions = swagger.getDefinitions(); + for(String name: definitions.keySet()) { + Model model = definitions.get(name); + Map modelMap = new HashMap(); + modelMap.put(name, model); + Map models = processModels(config, modelMap); + models.putAll(config.additionalProperties()); + + allModels.add(((List)models.get("models")).get(0)); + + for(String templateName : config.modelTemplateFiles().keySet()) { + String suffix = config.modelTemplateFiles().get(templateName); + String filename = config.modelFileFolder() + File.separator + config.toModelFilename(name) + suffix; + String template = readTemplate(config.templateDir() + File.separator + templateName); + Template tmpl = Mustache.compiler() + .withLoader(new Mustache.TemplateLoader() { + public Reader getTemplate (String name) { + return getTemplateReader(config.templateDir() + File.separator + name + ".mustache"); + }; + }) + .defaultValue("") + .compile(template); + writeToFile(filename, tmpl.execute(models)); + } + } + if(System.getProperty("debugModels") != null) { + System.out.println("############ Model info ############"); + Json.prettyPrint(allModels); + } + + // apis + Map> paths = processPaths(swagger.getPaths()); + for(String tag : paths.keySet()) { + List ops = paths.get(tag); + Map operation = processOperations(config, tag, ops); + operation.put("basePath", basePath); + operation.put("baseName", tag); + operation.put("modelPackage", config.modelPackage()); + operation.putAll(config.additionalProperties()); + operation.put("classname", config.toApiName(tag)); + allOperations.add(operation); + for(String templateName : config.apiTemplateFiles().keySet()) { + String suffix = config.apiTemplateFiles().get(templateName); + String filename = config.apiFileFolder() + + File.separator + + config.toApiFilename(tag) + + suffix; + + String template = readTemplate(config.templateDir() + File.separator + templateName); + Template tmpl = Mustache.compiler() + .withLoader(new Mustache.TemplateLoader() { + public Reader getTemplate (String name) { + return getTemplateReader(config.templateDir() + File.separator + name + ".mustache"); + }; + }) + .defaultValue("") + .compile(template); + + writeToFile(filename, tmpl.execute(operation)); + } + } + if(System.getProperty("debugOperations") != null) { + System.out.println("############ Operation info ############"); + Json.prettyPrint(allOperations); + } + + // supporting files + Map bundle = new HashMap(); + bundle.putAll(config.additionalProperties()); + bundle.put("apiPackage", config.apiPackage()); + + Map apis = new HashMap(); + apis.put("apis", allOperations); + if(swagger.getBasePath() != null) { + bundle.put("basePath", swagger.getBasePath()); + } + bundle.put("apiInfo", apis); + bundle.put("models", allModels); + bundle.put("apiFolder", config.apiPackage().replaceAll("\\.", "/")); + bundle.put("modelPackage", config.modelPackage()); + if (swagger.getExternalDocs() != null) { + bundle.put("externalDocs", swagger.getExternalDocs()); + } + for(int i = 0; i < allModels.size() - 1; i++) { + HashMap cm = (HashMap) allModels.get(i); + CodegenModel m = cm.get("model"); + m.hasMoreModels = true; + } + + if(System.getProperty("debugSupportingFiles") != null) { + System.out.println("############ Supporting file info ############"); + Json.prettyPrint(bundle); + } + + for(SupportingFile support : config.supportingFiles()) { + String outputFolder = config.outputFolder(); + if(support.folder != null && !"".equals(support.folder)) + outputFolder += File.separator + support.folder; + File of = new File(outputFolder); + if(!of.isDirectory()) + of.mkdirs(); + String outputFilename = outputFolder + File.separator + support.destinationFilename; + + if(support.templateFile.endsWith("mustache")) { + String template = readTemplate(config.templateDir() + File.separator + support.templateFile); + Template tmpl = Mustache.compiler() + .withLoader(new Mustache.TemplateLoader() { + public Reader getTemplate (String name) { + return getTemplateReader(config.templateDir() + File.separator + name + ".mustache"); + }; + }) + .defaultValue("") + .compile(template); + + writeToFile(outputFilename, tmpl.execute(bundle)); + } + else { + String template = readTemplate(config.templateDir() + File.separator + support.templateFile); + FileUtils.writeStringToFile(new File(outputFilename), template); + System.out.println("copying file to " + outputFilename); + } + } + + config.processSwagger(swagger); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public Map> processPaths(Map paths) { + Map> ops = new HashMap>(); + List tags = null; + + for(String resourcePath : paths.keySet()) { + Path path = paths.get(resourcePath); + processOperation(resourcePath, "get", path.getGet(), ops); + processOperation(resourcePath, "put", path.getPut(), ops); + processOperation(resourcePath, "post", path.getPost(), ops); + processOperation(resourcePath, "delete", path.getDelete(), ops); + processOperation(resourcePath, "patch", path.getPatch(), ops); + processOperation(resourcePath, "options", path.getOptions(), ops); + } + return ops; + } + + public void processOperation(String resourcePath, String httpMethod, Operation operation, Map> operations) { + if(operation != null) { + List tags = operation.getTags(); + if(tags == null) { + tags = new ArrayList(); + tags.add("default"); + } + + for(String tag : tags) { + CodegenOperation co = config.fromOperation(resourcePath, httpMethod, operation); + co.tags = new ArrayList(); + co.tags.add(sanitizeTag(tag)); + + config.addOperationToGroup(sanitizeTag(tag), resourcePath, operation, co, operations); + } + } + } + + protected String sanitizeTag(String tag) { + // remove spaces and make strong case + String [] parts = tag.split(" "); + StringBuffer buf = new StringBuffer(); + for(String part: parts) { + if(!"".equals(part)) { + buf.append(Character.toUpperCase(part.charAt(0))); + if(part.length() > 1) + buf.append(part.substring(1)); + } + } + return buf.toString().replaceAll("[^a-zA-Z ]", ""); + } + + public File writeToFile(String filename, String contents) throws IOException { + System.out.println("writing file " + filename); + File output = new File(filename); + + if(output.getParent() != null && !new File(output.getParent()).exists()) { + File parent = new File(output.getParent()); + parent.mkdirs(); + } + Writer out = new BufferedWriter(new OutputStreamWriter( + new FileOutputStream(output), "UTF-8")); + + out.write(contents); + out.close(); + return output; + } + + public String readTemplate(String name) { + try{ + Reader reader = getTemplateReader(name); + if(reader == null) + throw new RuntimeException("no file found"); + java.util.Scanner s = new java.util.Scanner(reader).useDelimiter("\\A"); + return s.hasNext() ? s.next() : ""; + } + catch(Exception e) { + e.printStackTrace(); + } + throw new RuntimeException("can't load template " + name); + } + + public Reader getTemplateReader(String name) { + try{ + InputStream is = this.getClass().getClassLoader().getResourceAsStream(getCPResourcePath(name)); + if(is == null) + is = new FileInputStream(new File(name)); + if(is == null) + throw new RuntimeException("no file found"); + return new InputStreamReader(is); + } + catch(Exception e) { + e.printStackTrace(); + } + throw new RuntimeException("can't load template " + name); + } + + private String getCPResourcePath(String name) { + if (!"/".equals(File.separator)) + return name.replaceAll(Pattern.quote(File.separator), "/"); + return name; + } + +public Map processOperations(CodegenConfig config, String tag, List ops) { + Map operations = new HashMap(); + Map objs = new HashMap(); + objs.put("classname", config.toApiName(tag)); + objs.put("operation", ops); + operations.put("operations", objs); + operations.put("package", config.apiPackage()); + + Set allImports = new HashSet(); + for(CodegenOperation op: ops) { + allImports.addAll(op.imports); + } + + List> imports = new ArrayList>(); + for(String i: allImports) { + Map im = new HashMap(); + String m = config.importMapping().get(i); + if(m == null) + m = config.toModelImport(i); + if(m != null) { + im.put("import", m); + imports.add(im); + } + } + + operations.put("imports", imports); + config.postProcessOperations(operations); + return operations; + } + + public Map processModels(CodegenConfig config, Map definitions) { + Map objs = new HashMap(); + objs.put("package", config.modelPackage()); + List models = new ArrayList(); + List model = new ArrayList(); + Set allImports = new HashSet(); + for(String key: definitions.keySet()) { + Model mm = definitions.get(key); + CodegenModel cm = config.fromModel(key, mm); + Map mo = new HashMap(); + mo.put("model", cm); + models.add(mo); + allImports.addAll(cm.imports); + } + objs.put("models", models); + + List> imports = new ArrayList>(); + for(String i: allImports) { + Map im = new HashMap(); + String m = config.importMapping().get(i); + if(m == null) + m = config.toModelImport(i); + if(m != null && !config.defaultIncludes().contains(m)) { + im.put("import", m); + imports.add(im); + } + // add instantiation types + m = config.instantiationTypes().get(i); + if(m != null && !config.defaultIncludes().contains(m)) { + im.put("import", m); + imports.add(im); + } + } + + objs.put("imports", imports); + config.postProcessModels(objs); + + return objs; + } +} diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/Generator.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/Generator.java new file mode 100644 index 00000000000..929ae580991 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/Generator.java @@ -0,0 +1,8 @@ +package com.wordnik.swagger.codegen; + +import com.wordnik.swagger.models.Swagger; + +public interface Generator { + Generator opts(ClientOptInput opts); + void generate(); +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/SupportingFile.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/SupportingFile.java new file mode 100644 index 00000000000..85f08bfa70c --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/SupportingFile.java @@ -0,0 +1,13 @@ +package com.wordnik.swagger.codegen; + +public class SupportingFile { + public String templateFile; + public String folder; + public String destinationFilename; + + public SupportingFile(String templateFile, String folder, String destinationFilename) { + this.templateFile = templateFile; + this.folder = folder; + this.destinationFilename = destinationFilename; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/auth/AuthMethod.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/auth/AuthMethod.java new file mode 100644 index 00000000000..7de102ec350 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/auth/AuthMethod.java @@ -0,0 +1,6 @@ +package com.wordnik.swagger.codegen.auth; + +public interface AuthMethod { + String getType(); + void setType(String type); +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/haproxy.cfg b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/haproxy.cfg new file mode 100644 index 00000000000..9fd8d61f2ce --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/haproxy.cfg @@ -0,0 +1,86 @@ +#--------------------------------------------------------------------- +# Global settings +#--------------------------------------------------------------------- +global + log 127.0.0.1 local2 + chroot /var/lib/haproxy + pidfile /var/run/haproxy.pid + maxconn 4000 + user haproxy + group haproxy + daemon + +#--------------------------------------------------------------------- +# common defaults that all the 'listen' and 'backend' sections will +# use if not designated in their block +#--------------------------------------------------------------------- +defaults + mode http + log global + option dontlognull + option httpclose + option httplog + option forwardfor + option redispatch + timeout connect 10000 # default 10 second time out if a backend is not found + timeout client 300000 + timeout server 300000 + maxconn 60000 + retries 3 + +#--------------------------------------------------------------------- +# main frontend which proxys to the backends +#--------------------------------------------------------------------- +frontend main *:80 + default_backend app + + acl is_swagger_online hdr_beg(host) -i online.swagger.io + acl is_swagger_io hdr_beg(host) -i swagger.io + acl is_old hdr_beg(host) -i swagger.wordnik.com + acl is_old_editor hdr_beg(host) -i editor.swagger.wordnik.com + acl is_validator_swagger path_beg /swagger.json + + # online spec validator + reqrep ([^\ ]*)\ /validator/(.*) \1\ /validator/validator/\2 if is_swagger_online + + # something that didn't work + reqrep ([^\ ]*)\ /swagger.json(.*) \1\ /validator/swagger.json if is_validator_swagger + + # swagger schema + reqrep ^([^\ :]*)\ /v2/schema.json(.*) \1\ /swagger-api/swagger-spec/master/schemas/v2.0/schema.json\2 + acl is_swagger_spec path_beg /swagger-api/swagger-spec + + # swagger docs + reqrep ^([^\ :]*)\ /swagger-core/documentation/annotations/apidocs/current(.*) \1\ /swagger-core/apidocs/\2 + acl is_swagger_docs path_beg /swagger-core/apidocs + + use_backend github_swagger_io if is_swagger_docs + use_backend validator if is_swagger_online + use_backend validator if is_validator_swagger + use_backend github_swagger_io if is_swagger_io !is_swagger_spec + use_backend github_swagger_spec if is_swagger_spec + + redirect location http://editor.swagger.io if is_old_editor + redirect location http://swagger.io if is_old + +#--------------------------------------------------------------------- +# round robin balancing between the various backends +#--------------------------------------------------------------------- +backend github_swagger_io + balance roundrobin + server gh1 swagger-api.github.io:80 check + +backend github_swagger_spec + http-request set-header Host raw.githubusercontent.com + rspirep ^Content-type:(.*) Content-Type:\ application/json + rspirep ^Access-Control-Allow-Origin:(.*) Access-Control-Allow-Origin:* + balance roundrobin + server gh2 raw.githubusercontent.com:443 check ssl verify none + +backend validator + balance roundrobin + server app1 127.0.0.1:8000 check + +backend app + balance roundrobin + server app1 127.0.0.1:8000 check diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/AndroidClientCodegen.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/AndroidClientCodegen.java new file mode 100644 index 00000000000..754ab46ac15 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/AndroidClientCodegen.java @@ -0,0 +1,106 @@ +package com.wordnik.swagger.codegen.languages; + +import com.wordnik.swagger.codegen.*; +import com.wordnik.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class AndroidClientCodegen extends DefaultCodegen implements CodegenConfig { + protected String invokerPackage = "com.wordnik.client"; + protected String groupId = "com.wordnik"; + protected String artifactId = "swagger-client"; + protected String artifactVersion = "1.0.0"; + protected String sourceFolder = "src/main/java"; + + public String getName() { + return "android"; + } + + public String getHelp() { + return "Generates an Android client library."; + } + + public AndroidClientCodegen() { + super(); + outputFolder = "generated-code/android"; + modelTemplateFiles.put("model.mustache", ".java"); + apiTemplateFiles.put("api.mustache", ".java"); + templateDir = "android-java"; + apiPackage = "com.wordnik.client.api"; + modelPackage = "com.wordnik.client.model"; + + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + + supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + supportingFiles.add(new SupportingFile("apiInvoker.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "ApiInvoker.java")); + supportingFiles.add(new SupportingFile("httpPatch.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "HttpPatch.java")); + supportingFiles.add(new SupportingFile("jsonUtil.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "JsonUtil.java")); + supportingFiles.add(new SupportingFile("apiException.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "ApiException.java")); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "String", + "boolean", + "Boolean", + "Double", + "Integer", + "Long", + "Float", + "Object") + ); + instantiationTypes.put("array", "ArrayList"); + instantiationTypes.put("map", "HashMap"); + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String apiFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + apiPackage().replaceAll("\\.", "/"); + } + + public String modelFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + modelPackage().replaceAll("\\.", "/"); + } + + @Override + public String getTypeDeclaration(Property p) { + if(p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + Property inner = ap.getItems(); + return getSwaggerType(p) + "<" + getTypeDeclaration(inner) + ">"; + } + else if (p instanceof MapProperty) { + MapProperty mp = (MapProperty) p; + Property inner = mp.getAdditionalProperties(); + + return getSwaggerType(p) + ""; + } + return super.getTypeDeclaration(p); + } + + @Override + public String getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) + return toModelName(type); + } + else + type = swaggerType; + return toModelName(type); + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/JavaClientCodegen.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/JavaClientCodegen.java new file mode 100644 index 00000000000..ab710431b78 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/JavaClientCodegen.java @@ -0,0 +1,115 @@ +package com.wordnik.swagger.codegen.languages; + +import com.wordnik.swagger.codegen.*; +import com.wordnik.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig { + protected String invokerPackage = "io.swagger.client"; + protected String groupId = "io.swagger"; + protected String artifactId = "swagger-client"; + protected String artifactVersion = "1.0.0"; + protected String sourceFolder = "src/main/java"; + + public String getName() { + return "java"; + } + + public String getHelp() { + return "Generates a Java client library."; + } + + public JavaClientCodegen() { + super(); + outputFolder = "generated-code/java"; + modelTemplateFiles.put("model.mustache", ".java"); + apiTemplateFiles.put("api.mustache", ".java"); + templateDir = "Java"; + apiPackage = "io.swagger.client.api"; + modelPackage = "io.swagger.client.model"; + + reservedWords = new HashSet ( + Arrays.asList( + "abstract", "continue", "for", "new", "switch", "assert", + "default", "if", "package", "synchronized", "boolean", "do", "goto", "private", + "this", "break", "double", "implements", "protected", "throw", "byte", "else", + "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", + "catch", "extends", "int", "short", "try", "char", "final", "interface", "static", + "void", "class", "finally", "long", "strictfp", "volatile", "const", "float", + "native", "super", "while") + ); + + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + + supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + supportingFiles.add(new SupportingFile("apiInvoker.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "ApiInvoker.java")); + supportingFiles.add(new SupportingFile("JsonUtil.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "JsonUtil.java")); + supportingFiles.add(new SupportingFile("apiException.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "ApiException.java")); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "String", + "boolean", + "Boolean", + "Double", + "Integer", + "Long", + "Float", + "Object") + ); + instantiationTypes.put("array", "ArrayList"); + instantiationTypes.put("map", "HashMap"); + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String apiFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + apiPackage().replaceAll("\\.", "/"); + } + + public String modelFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + modelPackage().replaceAll("\\.", "/"); + } + + @Override + public String getTypeDeclaration(Property p) { + if(p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + Property inner = ap.getItems(); + return getSwaggerType(p) + "<" + getTypeDeclaration(inner) + ">"; + } + else if (p instanceof MapProperty) { + MapProperty mp = (MapProperty) p; + Property inner = mp.getAdditionalProperties(); + + return getSwaggerType(p) + ""; + } + return super.getTypeDeclaration(p); + } + + @Override + public String getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) + return toModelName(type); + } + else + type = swaggerType; + return toModelName(type); + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/JaxRSServerCodegen.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/JaxRSServerCodegen.java new file mode 100644 index 00000000000..6c805e993c9 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/JaxRSServerCodegen.java @@ -0,0 +1,129 @@ +package com.wordnik.swagger.codegen.languages; + +import com.wordnik.swagger.models.Operation; +import com.wordnik.swagger.models.Path; +import com.wordnik.swagger.util.Json; +import com.wordnik.swagger.codegen.*; +import com.wordnik.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class JaxRSServerCodegen extends JavaClientCodegen implements CodegenConfig { + protected String invokerPackage = "com.wordnik.api"; + protected String groupId = "com.wordnik"; + protected String artifactId = "swagger-server"; + protected String artifactVersion = "1.0.0"; + protected String sourceFolder = "src/main/java"; + protected String title = "Swagger Server"; + + public String getName() { + return "jaxrs"; + } + + public String getHelp() { + return "Generates a Java JAXRS Server application."; + } + + public JaxRSServerCodegen() { + super(); + outputFolder = "generated-code/javaJaxRS"; + modelTemplateFiles.put("model.mustache", ".java"); + apiTemplateFiles.put("api.mustache", ".java"); + templateDir = "JavaJaxRS"; + apiPackage = "com.wordnik.api"; + modelPackage = "com.wordnik.model"; + + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + additionalProperties.put("title", title); + + supportingFiles.clear(); + supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + supportingFiles.add(new SupportingFile("ApiException.mustache", + (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "ApiException.java")); + supportingFiles.add(new SupportingFile("ApiOriginFilter.mustache", + (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "ApiOriginFilter.java")); + supportingFiles.add(new SupportingFile("ApiResponseMessage.mustache", + (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "ApiResponseMessage.java")); + supportingFiles.add(new SupportingFile("NotFoundException.mustache", + (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "NotFoundException.java")); + supportingFiles.add(new SupportingFile("web.mustache", + ("src/main/webapp/WEB-INF"), "web.xml")); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "String", + "boolean", + "Boolean", + "Double", + "Integer", + "Long", + "Float") + ); + } + + @Override + public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map> operations) { + String basePath = resourcePath; + if(basePath.startsWith("/")) + basePath = basePath.substring(1); + int pos = basePath.indexOf("/"); + if(pos > 0) + basePath = basePath.substring(0, pos); + + if(basePath == "") + basePath = "default"; + else { + if(co.path.startsWith("/" + basePath)) + co.path = co.path.substring(("/" + basePath).length()); + co.subresourceOperation = !co.path.isEmpty(); + } + List opList = operations.get(basePath); + if(opList == null) { + opList = new ArrayList(); + operations.put(basePath, opList); + } + opList.add(co); + co.baseName = basePath; + } + + public Map postProcessOperations(Map objs) { + Map operations = (Map)objs.get("operations"); + if(operations != null) { + List ops = (List) operations.get("operation"); + for(CodegenOperation operation : ops) { + if(operation.returnType == null) + operation.returnType = "Void"; + else if(operation.returnType.startsWith("List")) { + String rt = operation.returnType; + int end = rt.lastIndexOf(">"); + if(end > 0) { + operation.returnType = rt.substring("List<".length(), end); + operation.returnContainer = "List"; + } + } + else if(operation.returnType.startsWith("Map")) { + String rt = operation.returnType; + int end = rt.lastIndexOf(">"); + if(end > 0) { + operation.returnType = rt.substring("Map<".length(), end); + operation.returnContainer = "Map"; + } + } + else if(operation.returnType.startsWith("Set")) { + String rt = operation.returnType; + int end = rt.lastIndexOf(">"); + if(end > 0) { + operation.returnType = rt.substring("Set<".length(), end); + operation.returnContainer = "Set"; + } + } + } + } + return objs; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/NodeJSServerCodegen.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/NodeJSServerCodegen.java new file mode 100644 index 00000000000..b2f82498989 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/NodeJSServerCodegen.java @@ -0,0 +1,79 @@ +package com.wordnik.swagger.codegen.languages; + +import com.wordnik.swagger.codegen.*; +import com.wordnik.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class NodeJSServerCodegen extends DefaultCodegen implements CodegenConfig { + protected String invokerPackage = "com.wordnik.client"; + protected String groupId = "com.wordnik"; + protected String artifactId = "swagger-client"; + protected String artifactVersion = "1.0.0"; + + public String getName() { + return "nodejs"; + } + + public String getHelp() { + return "Generates a node.js server application compatible with the 1.2 swagger specification."; + } + + public NodeJSServerCodegen() { + super(); + outputFolder = "generated-code/nodejs"; + apiTemplateFiles.put("api.mustache", ".js"); + templateDir = "nodejs"; + apiPackage = "app.apis"; + modelPackage = "app"; + + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + + supportingFiles.add(new SupportingFile("package.mustache", "", "package.json")); + supportingFiles.add(new SupportingFile("models.mustache", modelPackage, "models.js")); + supportingFiles.add(new SupportingFile("main.mustache", "", "main.js")); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.js")); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "String", + "boolean", + "Boolean", + "Double", + "Integer", + "Long", + "Float") + ); + typeMapping.put("array", "array"); + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separator + apiPackage().replaceAll("\\.", File.separator); + } + + public String modelFileFolder() { + return outputFolder + File.separator + modelPackage().replaceAll("\\.", File.separator); + } + + @Override + public String getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + return typeMapping.get(swaggerType); + } + else + type = swaggerType; + return toModelName(type); + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/ObjcClientCodegen.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/ObjcClientCodegen.java new file mode 100644 index 00000000000..271c353b233 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/ObjcClientCodegen.java @@ -0,0 +1,216 @@ +package com.wordnik.swagger.codegen.languages; + +import com.wordnik.swagger.util.Json; +import com.wordnik.swagger.codegen.*; +import com.wordnik.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class ObjcClientCodegen extends DefaultCodegen implements CodegenConfig { + protected Set foundationClasses = new HashSet(); + protected String sourceFolder = "client"; + protected static String PREFIX = "SWG"; + + public String getName() { + return "objc"; + } + + public String getHelp() { + return "Generates an Objective-C client library."; + } + + public ObjcClientCodegen() { + super(); + outputFolder = "generated-code/objc"; + modelTemplateFiles.put("model-header.mustache", ".h"); + modelTemplateFiles.put("model-body.mustache", ".m"); + apiTemplateFiles.put("api-header.mustache", ".h"); + apiTemplateFiles.put("api-body.mustache", ".m"); + templateDir = "objc"; + modelPackage = ""; + + defaultIncludes = new HashSet( + Arrays.asList( + "bool", + "int", + "NSString", + "NSObject", + "NSArray", + "NSNumber", + "NSDictionary", + "NSMutableArray", + "NSMutableDictionary") + ); + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "NSNumber", + "NSString", + "NSObject", + "bool") + ); + + reservedWords = new HashSet( + Arrays.asList( + "void", "char", "short", "int", "void", "char", "short", "int", + "long", "float", "double", "signed", "unsigned", "id", "const", + "volatile", "in", "out", "inout", "bycopy", "byref", "oneway", + "self", "super" + )); + + typeMapping = new HashMap(); + typeMapping.put("enum", "NSString"); + typeMapping.put("Date", "SWGDate"); + typeMapping.put("DateTime", "SWGDate"); + // typeMapping.put("Date", "SWGDate"); + typeMapping.put("boolean", "NSNumber"); + typeMapping.put("string", "NSString"); + typeMapping.put("integer", "NSNumber"); + typeMapping.put("int", "NSNumber"); + typeMapping.put("float", "NSNumber"); + typeMapping.put("long", "NSNumber"); + typeMapping.put("double", "NSNumber"); + typeMapping.put("array", "NSArray"); + typeMapping.put("map", "NSDictionary"); + typeMapping.put("number", "NSNumber"); + typeMapping.put("List", "NSArray"); + typeMapping.put("object", "NSObject"); + + importMapping = new HashMap (); + importMapping.put("Date", "SWGDate"); + + foundationClasses = new HashSet ( + Arrays.asList( + "NSNumber", + "NSObject", + "NSString", + "NSDictionary") + ); + + instantiationTypes.put("array", "NSMutableArray"); + instantiationTypes.put("map", "NSMutableDictionary"); + + supportingFiles.add(new SupportingFile("SWGObject.h", sourceFolder, "SWGObject.h")); + supportingFiles.add(new SupportingFile("SWGObject.m", sourceFolder, "SWGObject.m")); + supportingFiles.add(new SupportingFile("SWGApiClient.h", sourceFolder, "SWGApiClient.h")); + supportingFiles.add(new SupportingFile("SWGApiClient.m", sourceFolder, "SWGApiClient.m")); + supportingFiles.add(new SupportingFile("SWGFile.h", sourceFolder, "SWGFile.h")); + supportingFiles.add(new SupportingFile("SWGFile.m", sourceFolder, "SWGFile.m")); + supportingFiles.add(new SupportingFile("SWGDate.h", sourceFolder, "SWGDate.h")); + supportingFiles.add(new SupportingFile("SWGDate.m", sourceFolder, "SWGDate.m")); + supportingFiles.add(new SupportingFile("Podfile.mustache", "", "Podfile")); + } + + @Override + public String toInstantiationType(Property p) { + if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + String inner = getSwaggerType(ap.getAdditionalProperties()); + return instantiationTypes.get("map"); + } + else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + return instantiationTypes.get("array"); + } + else + return null; + } + + @Override + public String getTypeDeclaration(String name) { + if(languageSpecificPrimitives.contains(name) && !foundationClasses.contains(name)) + return name; + else + return name + "*"; + } + + @Override + public String getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type) && !foundationClasses.contains(type)) + return toModelName(type); + } + else + type = swaggerType; + return toModelName(type); + } + + @Override + public String getTypeDeclaration(Property p) { + String swaggerType = getSwaggerType(p); + if(languageSpecificPrimitives.contains(swaggerType) && !foundationClasses.contains(swaggerType)) + return toModelName(swaggerType); + else + return swaggerType + "*"; + } + + @Override + public String toModelName(String type) { + if(typeMapping.keySet().contains(type) || + foundationClasses.contains(type) || + importMapping.values().contains(type) || + defaultIncludes.contains(type) || + languageSpecificPrimitives.contains(type)) { + return Character.toUpperCase(type.charAt(0)) + type.substring(1); + } + else { + return PREFIX + Character.toUpperCase(type.charAt(0)) + type.substring(1); + } + } + + @Override + public String toModelImport(String name) { + // name = name + ".h"; + if("".equals(modelPackage())) + return name; + else + return modelPackage() + "." + name; + } + + @Override + public String toDefaultValue(Property p) { + return null; + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separator + sourceFolder; + } + + @Override + public String modelFileFolder() { + return outputFolder + File.separator + sourceFolder; + } + + @Override + public String toModelFilename(String name) { + return PREFIX + initialCaps(name); + } + + @Override + public String toApiName(String name) { + return PREFIX + initialCaps(name) + "Api"; + } + + public String toApiFilename(String name) { + return PREFIX + initialCaps(name) + "Api"; + } + + @Override + public String toVarName(String name) { + String paramName = name.replaceAll("[^a-zA-Z0-9_]",""); + if(paramName.startsWith("new") || reservedWords.contains(paramName)) { + return escapeReservedWord(paramName); + } + else + return paramName; + } + + public String escapeReservedWord(String name) { + return "_" + name; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/PhpClientCodegen.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/PhpClientCodegen.java new file mode 100644 index 00000000000..f27044c2db7 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/PhpClientCodegen.java @@ -0,0 +1,110 @@ +package com.wordnik.swagger.codegen.languages; + +import com.wordnik.swagger.codegen.*; +import com.wordnik.swagger.util.Json; +import com.wordnik.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class PhpClientCodegen extends DefaultCodegen implements CodegenConfig { + protected String invokerPackage = "com.wordnik.client"; + protected String groupId = "com.wordnik"; + protected String artifactId = "swagger-client"; + protected String artifactVersion = "1.0.0"; + // protected String sourceFolder = ""; + + public String getName() { + return "php"; + } + + public String getHelp() { + return "Generates a PHP client library."; + } + + public PhpClientCodegen() { + super(); + outputFolder = "generated-code/php"; + modelTemplateFiles.put("model.mustache", ".php"); + apiTemplateFiles.put("api.mustache", ".php"); + templateDir = "php"; + + typeMapping.clear(); + languageSpecificPrimitives.clear(); + + reservedWords = new HashSet ( + Arrays.asList( + "int") + ); + + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + + languageSpecificPrimitives.add("int"); + languageSpecificPrimitives.add("array"); + languageSpecificPrimitives.add("map"); + languageSpecificPrimitives.add("string"); + languageSpecificPrimitives.add("DateTime"); + + typeMapping.put("long", "int"); + typeMapping.put("integer", "int"); + typeMapping.put("Array", "array"); + typeMapping.put("String", "string"); + typeMapping.put("List", "array"); + typeMapping.put("map", "map"); + + supportingFiles.add(new SupportingFile("Swagger.mustache", "", "Swagger.php")); + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String apiFileFolder() { + return outputFolder + "/" + apiPackage().replaceAll("\\.", "/"); + } + + public String modelFileFolder() { + return outputFolder + "/" + modelPackage().replaceAll("\\.", "/"); + } + + @Override + public String getTypeDeclaration(Property p) { + if(p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + Property inner = ap.getItems(); + return getSwaggerType(p) + "[" + getTypeDeclaration(inner) + "]"; + } + else if (p instanceof MapProperty) { + MapProperty mp = (MapProperty) p; + Property inner = mp.getAdditionalProperties(); + return getSwaggerType(p) + "[string," + getTypeDeclaration(inner) + "]"; + } + return super.getTypeDeclaration(p); + } + + @Override + public String getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) { + return type; + } + } + else + type = swaggerType; + if(type == null) + return null; + return type; + } + + public String toDefaultValue(Property p) { + return "null"; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/PythonClientCodegen.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/PythonClientCodegen.java new file mode 100755 index 00000000000..c3cf3648123 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/PythonClientCodegen.java @@ -0,0 +1,117 @@ +/** + * Copyright 2014 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.languages; + +import com.wordnik.swagger.codegen.*; +import com.wordnik.swagger.models.properties.*; + +public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig { + + public String getName() { + return "python"; + } + + public String getHelp() { + return "Generates a Python client library."; + } + + public PythonClientCodegen() { + super(); + outputFolder = "generated-code/python"; + modelTemplateFiles.put("model.mustache", ".py"); + apiTemplateFiles.put("api.mustache", ".py"); + templateDir = "python"; + + apiPackage = ""; + modelPackage = "models"; + + languageSpecificPrimitives.clear(); + languageSpecificPrimitives.add("int"); + languageSpecificPrimitives.add("float"); + languageSpecificPrimitives.add("long"); + languageSpecificPrimitives.add("list"); + languageSpecificPrimitives.add("bool"); + languageSpecificPrimitives.add("str"); + languageSpecificPrimitives.add("datetime"); + + typeMapping.clear(); + typeMapping.put("integer", "int"); + typeMapping.put("float", "float"); + typeMapping.put("long", "long"); + typeMapping.put("double", "float"); + typeMapping.put("array", "list"); + typeMapping.put("map", "map"); + typeMapping.put("boolean", "bool"); + typeMapping.put("string", "str"); + typeMapping.put("date", "datetime"); + + + supportingFiles.add(new SupportingFile("swagger.mustache", "", "swagger.py")); + supportingFiles.add(new SupportingFile("__init__.mustache", "", "__init__.py")); + supportingFiles.add(new SupportingFile("__init__.mustache", modelPackage, "__init__.py")); + + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String apiFileFolder() { + return outputFolder + "/" + apiPackage().replaceAll("\\.", "/"); + } + + public String modelFileFolder() { + return outputFolder + "/" + modelPackage().replaceAll("\\.", "/"); + } + + @Override + public String getTypeDeclaration(Property p) { + if(p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + Property inner = ap.getItems(); + return getSwaggerType(p) + "[" + getTypeDeclaration(inner) + "]"; + } + else if (p instanceof MapProperty) { + MapProperty mp = (MapProperty) p; + Property inner = mp.getAdditionalProperties(); + + return getSwaggerType(p) + "(String, " + getTypeDeclaration(inner) + ")"; + } + return super.getTypeDeclaration(p); + } + + @Override + public String getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) { + return type; + } + } + else + type = swaggerType; + return type; + } + + public String toDefaultValue(Property p) { + // TODO: Support Python def value + return "null"; + } +} diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/ScalaClientCodegen.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/ScalaClientCodegen.java new file mode 100644 index 00000000000..6c845a9ccb7 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/ScalaClientCodegen.java @@ -0,0 +1,182 @@ +package com.wordnik.swagger.codegen.languages; + +import com.wordnik.swagger.codegen.*; +import com.wordnik.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class ScalaClientCodegen extends DefaultCodegen implements CodegenConfig { + protected String invokerPackage = "io.swagger.client"; + protected String groupId = "com.wordnik"; + protected String artifactId = "swagger-client"; + protected String artifactVersion = "1.0.0"; + protected String sourceFolder = "src/main/java"; + + public String getName() { + return "scala"; + } + + public String getHelp() { + return "Generates a Scala client library."; + } + + public ScalaClientCodegen() { + super(); + outputFolder = "generated-code/scala"; + modelTemplateFiles.put("model.mustache", ".scala"); + apiTemplateFiles.put("api.mustache", ".scala"); + templateDir = "scala"; + apiPackage = "io.swagger.client.api"; + modelPackage = "io.swagger.client.model"; + + reservedWords = new HashSet ( + Arrays.asList( + "abstract", "case", "catch", "class", "def", "do", "else", "extends", + "false", "final", "finally", "for", "forSome", "if", "implicit", + "import", "lazy", "match", "new", "null", "object", "override", "package", + "private", "protected", "return", "sealed", "super", "this", "throw", + "trait", "try", "true", "type", "val", "var", "while", "with", "yield") + ); + + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + + supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + supportingFiles.add(new SupportingFile("apiInvoker.mustache", + (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "ApiInvoker.scala")); + + importMapping.remove("List"); + importMapping.remove("Set"); + importMapping.remove("Map"); + + importMapping.put("DateTime", "org.joda.time.DateTime"); + importMapping.put("ListBuffer", "scala.collections.mutable.ListBuffer"); + + typeMapping = new HashMap(); + typeMapping.put("enum", "NSString"); + typeMapping.put("array", "List"); + typeMapping.put("set", "Set"); + typeMapping.put("boolean", "Boolean"); + typeMapping.put("string", "String"); + typeMapping.put("int", "Int"); + typeMapping.put("long", "Long"); + typeMapping.put("float", "Float"); + typeMapping.put("byte", "Byte"); + typeMapping.put("short", "Short"); + typeMapping.put("char", "Char"); + typeMapping.put("long", "Long"); + typeMapping.put("double", "Double"); + typeMapping.put("object", "Any"); + typeMapping.put("file", "File"); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "String", + "boolean", + "Boolean", + "Double", + "Int", + "Long", + "Float", + "Object", + "List", + "Map") + ); + instantiationTypes.put("array", "ListBuffer"); + instantiationTypes.put("map", "HashMap"); + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String apiFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + apiPackage().replaceAll("\\.", "/"); + } + + public String modelFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + modelPackage().replaceAll("\\.", "/"); + } + + @Override + public String getTypeDeclaration(Property p) { + if(p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + Property inner = ap.getItems(); + return getSwaggerType(p) + "[" + getTypeDeclaration(inner) + "]"; + } + else if (p instanceof MapProperty) { + MapProperty mp = (MapProperty) p; + Property inner = mp.getAdditionalProperties(); + + return getSwaggerType(p) + "[String, " + getTypeDeclaration(inner) + "]"; + } + return super.getTypeDeclaration(p); + } + + @Override + public String getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) + return toModelName(type); + } + else + type = swaggerType; + return toModelName(type); + } + + @Override + public String toInstantiationType(Property p) { + if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + String inner = getSwaggerType(ap.getAdditionalProperties()); + return instantiationTypes.get("map") + "[String, " + inner + "]"; + } + else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + return instantiationTypes.get("array") + "[" + inner + "]"; + } + else + return null; + } + + public String toDefaultValue(Property p) { + if(p instanceof StringProperty) + return "null"; + else if (p instanceof BooleanProperty) + return "null"; + else if(p instanceof DateProperty) + return "null"; + else if(p instanceof DateTimeProperty) + return "null"; + else if (p instanceof DoubleProperty) + return "null"; + else if (p instanceof FloatProperty) + return "null"; + else if (p instanceof IntegerProperty) + return "null"; + else if (p instanceof LongProperty) + return "null"; + else if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + String inner = getSwaggerType(ap.getAdditionalProperties()); + return "new HashMap[String, " + inner + "]() "; + } + else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + return "new ListBuffer[" + inner + "]() "; + } + else + return "null"; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/ScalatraServerCodegen.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/ScalatraServerCodegen.java new file mode 100644 index 00000000000..e87609b720d --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/ScalatraServerCodegen.java @@ -0,0 +1,174 @@ +package com.wordnik.swagger.codegen.languages; + +import com.wordnik.swagger.codegen.*; +import com.wordnik.swagger.models.properties.*; +import com.wordnik.swagger.util.Json; + +import java.util.*; +import java.io.File; + +public class ScalatraServerCodegen extends DefaultCodegen implements CodegenConfig { + protected String invokerPackage = "com.wordnik.client"; + protected String groupId = "com.wordnik"; + protected String artifactId = "swagger-client"; + protected String artifactVersion = "1.0.0"; + protected String sourceFolder = "src/main/scala"; + + public String getName() { + return "scalatra"; + } + + public String getHelp() { + return "Generates a Scala server application with Scalatra."; + } + + public ScalatraServerCodegen() { + super(); + outputFolder = "generated-code/scalatra"; + modelTemplateFiles.put("model.mustache", ".scala"); + apiTemplateFiles.put("api.mustache", ".scala"); + templateDir = "scalatra"; + apiPackage = "com.wordnik.client.api"; + modelPackage = "com.wordnik.client.model"; + + reservedWords = new HashSet ( + Arrays.asList( + "abstract", "continue", "for", "new", "switch", "assert", + "default", "if", "package", "synchronized", "boolean", "do", "goto", "private", + "this", "break", "double", "implements", "protected", "throw", "byte", "else", + "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", + "catch", "extends", "int", "short", "try", "char", "final", "interface", "static", + "void", "class", "finally", "long", "strictfp", "volatile", "const", "float", + "native", "super", "while") + ); + + defaultIncludes = new HashSet( + Arrays.asList("double", + "Int", + "Long", + "Float", + "Double", + "char", + "float", + "String", + "boolean", + "Boolean", + "Double", + "Integer", + "Long", + "Float", + "List", + "Set", + "Map") + ); + + typeMapping.put("integer", "Int"); + typeMapping.put("long", "Long"); + + additionalProperties.put("appName", "Swagger Sample"); + additionalProperties.put("appName", "Swagger Sample"); + additionalProperties.put("appDescription", "A sample swagger server"); + additionalProperties.put("infoUrl", "http://developers.helloreverb.com"); + additionalProperties.put("infoEmail", "hello@helloreverb.com"); + additionalProperties.put("licenseInfo", "All rights reserved"); + additionalProperties.put("licenseUrl", "http://apache.org/licenses/LICENSE-2.0.html"); + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + supportingFiles.add(new SupportingFile("build.sbt", "", "build.sbt")); + supportingFiles.add(new SupportingFile("web.xml", "/src/main/webapp/WEB-INF", "web.xml")); + supportingFiles.add(new SupportingFile("JettyMain.scala", sourceFolder, "JettyMain.scala")); + supportingFiles.add(new SupportingFile("Bootstrap.mustache", sourceFolder, "ScalatraBootstrap.scala")); + supportingFiles.add(new SupportingFile("ServletApp.mustache", sourceFolder, "ServletApp.scala")); + supportingFiles.add(new SupportingFile("project/build.properties", "project", "build.properties")); + supportingFiles.add(new SupportingFile("project/plugins.sbt", "project", "plugins.sbt")); + supportingFiles.add(new SupportingFile("sbt", "", "sbt")); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "String", + "boolean", + "Boolean", + "Double", + "Integer", + "Long", + "Float", + "Object") + ); + instantiationTypes.put("array", "ArrayList"); + instantiationTypes.put("map", "HashMap"); + + importMapping = new HashMap (); + importMapping.put("BigDecimal", "java.math.BigDecimal"); + importMapping.put("UUID", "java.util.UUID"); + importMapping.put("File", "java.io.File"); + importMapping.put("Date", "java.util.Date"); + importMapping.put("Timestamp", "java.sql.Timestamp"); + importMapping.put("Map", "java.util.Map"); + importMapping.put("HashMap", "java.util.HashMap"); + importMapping.put("Array", "java.util.List"); + importMapping.put("ArrayList", "java.util.ArrayList"); + importMapping.put("DateTime", "org.joda.time.DateTime"); + importMapping.put("LocalDateTime", "org.joda.time.LocalDateTime"); + importMapping.put("LocalDate", "org.joda.time.LocalDate"); + importMapping.put("LocalTime", "org.joda.time.LocalTime"); + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String apiFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + apiPackage().replaceAll("\\.", "/"); + } + + public String modelFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + modelPackage().replaceAll("\\.", "/"); + } + + @Override + public Map postProcessOperations(Map objs) { + Map operations = (Map) objs.get("operations"); + List operationList = (List) operations.get("operation"); + for(CodegenOperation op: operationList) { + op.httpMethod = op.httpMethod.toLowerCase(); + } + return objs; + } + + + @Override + public String getTypeDeclaration(Property p) { + if(p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + Property inner = ap.getItems(); + return getSwaggerType(p) + "[" + getTypeDeclaration(inner) + "]"; + } + else if (p instanceof MapProperty) { + MapProperty mp = (MapProperty) p; + Property inner = mp.getAdditionalProperties(); + + return getSwaggerType(p) + "[String, " + getTypeDeclaration(inner) + "]"; + } + return super.getTypeDeclaration(p); + } + + @Override + public String getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) + return toModelName(type); + } + else + type = swaggerType; + return toModelName(type); + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/StaticDocCodegen.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/StaticDocCodegen.java new file mode 100644 index 00000000000..3386a5f9fac --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/StaticDocCodegen.java @@ -0,0 +1,72 @@ +package com.wordnik.swagger.codegen.languages; + +import com.wordnik.swagger.codegen.*; +import com.wordnik.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class StaticDocCodegen extends DefaultCodegen implements CodegenConfig { + protected String invokerPackage = "com.wordnik.client"; + protected String groupId = "com.wordnik"; + protected String artifactId = "swagger-client"; + protected String artifactVersion = "1.0.0"; + protected String sourceFolder = "docs"; + + public String getName() { + return "dynamic-html"; + } + + public String getHelp() { + return "Generates a dynamic HTML site."; + } + + public StaticDocCodegen() { + super(); + outputFolder = "docs"; + modelTemplateFiles.put("model.mustache", ".html"); + apiTemplateFiles.put("operation.mustache", ".html"); + templateDir = "swagger-static"; + + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + + supportingFiles.add(new SupportingFile("package.mustache", "", "package.json")); + supportingFiles.add(new SupportingFile("main.mustache", "", "main.js")); + supportingFiles.add(new SupportingFile("assets/css/bootstrap-responsive.css", + outputFolder + "/assets/css", "bootstrap-responsive.css")); + supportingFiles.add(new SupportingFile("assets/css/bootstrap.css", + outputFolder + "/assets/css", "bootstrap.css")); + supportingFiles.add(new SupportingFile("assets/css/style.css", + outputFolder + "/assets/css", "style.css")); + supportingFiles.add(new SupportingFile("assets/images/logo.png", + outputFolder + "/assets/images", "logo.png")); + supportingFiles.add(new SupportingFile("assets/js/bootstrap.js", + outputFolder + "/assets/js", "bootstrap.js")); + supportingFiles.add(new SupportingFile("assets/js/jquery-1.8.3.min.js", + outputFolder + "/assets/js", "jquery-1.8.3.min.js")); + supportingFiles.add(new SupportingFile("assets/js/main.js", + outputFolder + "/assets/js", "main.js")); + supportingFiles.add(new SupportingFile("index.mustache", + outputFolder, "index.html")); + + instantiationTypes.put("array", "ArrayList"); + instantiationTypes.put("map", "HashMap"); + } + + @Override + public String escapeReservedWord(String name) { + return "_" + name; + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separator + sourceFolder + File.separator + "operations"; + } + + public String modelFileFolder() { + return outputFolder + File.separator + sourceFolder + File.separator + "models"; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/StaticHtmlGenerator.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/StaticHtmlGenerator.java new file mode 100644 index 00000000000..42ce9fe3604 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/StaticHtmlGenerator.java @@ -0,0 +1,81 @@ +package com.wordnik.swagger.codegen.languages; + +import com.wordnik.swagger.codegen.*; +import com.wordnik.swagger.models.properties.*; +import com.wordnik.swagger.util.Json; + +import java.util.*; +import java.io.File; + +public class StaticHtmlGenerator extends DefaultCodegen implements CodegenConfig { + protected String invokerPackage = "com.wordnik.client"; + protected String groupId = "com.wordnik"; + protected String artifactId = "swagger-client"; + protected String artifactVersion = "1.0.0"; + protected String sourceFolder = "src/main/scala"; + + public String getName() { + return "html"; + } + + public String getHelp() { + return "Generates a static HTML file."; + } + + public StaticHtmlGenerator() { + super(); + outputFolder = "docs"; + templateDir = "htmlDocs"; + + defaultIncludes = new HashSet(); + + String partner = "our Partner"; + + if(System.getProperty("partner") != null) + partner = System.getProperty("partner"); + + additionalProperties.put("partner", partner); + additionalProperties.put("appName", "Swagger Sample"); + additionalProperties.put("appDescription", "A sample swagger server"); + additionalProperties.put("infoUrl", "https://helloreverb.com"); + additionalProperties.put("infoEmail", "hello@helloreverb.com"); + additionalProperties.put("licenseInfo", "All rights reserved"); + additionalProperties.put("licenseUrl", "http://apache.org/licenses/LICENSE-2.0.html"); + additionalProperties.put("invokerPackage", invokerPackage); + additionalProperties.put("groupId", groupId); + additionalProperties.put("artifactId", artifactId); + additionalProperties.put("artifactVersion", artifactVersion); + + supportingFiles.add(new SupportingFile("index.mustache", "", "index.html")); + reservedWords = new HashSet(); + + languageSpecificPrimitives = new HashSet(); + importMapping = new HashMap (); + } + + @Override + public String getTypeDeclaration(Property p) { + if(p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + Property inner = ap.getItems(); + return getSwaggerType(p) + "[" + getTypeDeclaration(inner) + "]"; + } + else if (p instanceof MapProperty) { + MapProperty mp = (MapProperty) p; + Property inner = mp.getAdditionalProperties(); + + return getSwaggerType(p) + "[String, " + getTypeDeclaration(inner) + "]"; + } + return super.getTypeDeclaration(p); + } + + @Override + public Map postProcessOperations(Map objs) { + Map operations = (Map) objs.get("operations"); + List operationList = (List) operations.get("operation"); + for(CodegenOperation op: operationList) { + op.httpMethod = op.httpMethod.toLowerCase(); + } + return objs; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/SwaggerGenerator.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/SwaggerGenerator.java new file mode 100644 index 00000000000..49f5dc6bab4 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/SwaggerGenerator.java @@ -0,0 +1,38 @@ +package com.wordnik.swagger.codegen.languages; + +import com.wordnik.swagger.codegen.*; +import com.wordnik.swagger.util.*; +import com.wordnik.swagger.models.Swagger; + +import org.apache.commons.io.FileUtils; + +import java.io.File; + +public class SwaggerGenerator extends DefaultCodegen implements CodegenConfig { + public String getName() { + return "swagger"; + } + + public String getHelp() { + return "Creates a static swagger.json file."; + } + + public SwaggerGenerator() { + super(); + outputFolder = "generated-code/swagger"; + } + + @Override + public void processSwagger(Swagger swagger) { + String swaggerString = Json.pretty(swagger); + + try{ + String outputFile = outputFolder + File.separator + "swagger.json"; + FileUtils.writeStringToFile(new File(outputFile), swaggerString); + System.out.println("wrote file to " + outputFile); + } + catch(Exception e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/TizenClientCodegen.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/TizenClientCodegen.java new file mode 100644 index 00000000000..d91267758ee --- /dev/null +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/languages/TizenClientCodegen.java @@ -0,0 +1,243 @@ +package com.wordnik.swagger.codegen.languages; + +import com.wordnik.swagger.util.Json; +import com.wordnik.swagger.codegen.*; +import com.wordnik.swagger.models.properties.*; + +import java.util.*; +import java.io.File; + +public class TizenClientCodegen extends DefaultCodegen implements CodegenConfig { + protected Set foundationClasses = new HashSet(); + protected String sourceFolder = "client"; + protected static String PREFIX = "Sami"; + protected Map namespaces = new HashMap(); + + public String getName() { + return "tizen"; + } + + public String getHelp() { + return "Generates a Samsung Tizen C++ client library."; + } + + public TizenClientCodegen() { + super(); + outputFolder = "generated-code/tizen"; + modelTemplateFiles.put("model-header.mustache", ".h"); + modelTemplateFiles.put("model-body.mustache", ".cpp"); + apiTemplateFiles.put("api-header.mustache", ".h"); + apiTemplateFiles.put("api-body.mustache", ".cpp"); + templateDir = "tizen"; + modelPackage = ""; + + defaultIncludes = new HashSet( + Arrays.asList( + "bool", + "int", + "long") + ); + languageSpecificPrimitives = new HashSet(); + + additionalProperties().put("prefix", PREFIX); + + reservedWords = new HashSet( + // VERIFY + Arrays.asList( + "void", "char", "short", "int", "void", "char", "short", "int", + "long", "float", "double", "signed", "unsigned", "id", "const", + "volatile", "in", "out", "inout", "bycopy", "byref", "oneway", + "self", "super" + )); + + super.typeMapping = new HashMap(); + + typeMapping.put("Date", "DateTime"); + typeMapping.put("DateTime", "DateTime"); + typeMapping.put("string", "String"); + typeMapping.put("integer", "Integer"); + typeMapping.put("float", "Float"); + typeMapping.put("long", "Long"); + typeMapping.put("boolean", "Boolean"); + typeMapping.put("double", "Double"); + typeMapping.put("array", "IList"); + typeMapping.put("map", "HashMap"); + typeMapping.put("number", "Long"); + typeMapping.put("object", PREFIX + "Object"); + + importMapping = new HashMap(); + + namespaces = new HashMap (); + namespaces.put("DateTime", "Tizen::Base::DateTime"); + namespaces.put("Integer", "Tizen::Base::Integer"); + namespaces.put("Long", "Tizen::Base::Long"); + namespaces.put("Boolean", "Tizen::Base::Boolean"); + namespaces.put("Float", "Tizen::Base::Float"); + namespaces.put("String", "Tizen::Base::String"); + namespaces.put("Double", "Tizen::Base::Double"); + namespaces.put("IList", "Tizen::Base::Collection::IList"); + namespaces.put("HashMap", "Tizen::Base::Collection::HashMap"); + namespaces.put("ArrayList", "Tizen::Base::Collection::ArrayList"); + namespaces.put("JsonNumber", "Tizen::Web::Json"); + namespaces.put("JsonString", "Tizen::Web::Json"); + + foundationClasses = new HashSet ( + Arrays.asList( + "String", + "Integer", + "Float") + ); + supportingFiles.clear(); + supportingFiles.add(new SupportingFile("modelFactory.mustache", sourceFolder, PREFIX + "ModelFactory.h")); + supportingFiles.add(new SupportingFile("helpers-header.mustache", sourceFolder, PREFIX + "Helpers.h")); + supportingFiles.add(new SupportingFile("helpers-body.mustache", sourceFolder, PREFIX + "Helpers.cpp")); + supportingFiles.add(new SupportingFile("apiclient-header.mustache", sourceFolder, PREFIX + "ApiClient.h")); + supportingFiles.add(new SupportingFile("apiclient-body.mustache", sourceFolder, PREFIX + "ApiClient.cpp")); + supportingFiles.add(new SupportingFile("object.mustache", sourceFolder, PREFIX + "Object.h")); + supportingFiles.add(new SupportingFile("error-header.mustache", sourceFolder, PREFIX + "Error.h")); + supportingFiles.add(new SupportingFile("error-body.mustache", sourceFolder, PREFIX + "Error.cpp")); + } + + @Override + public String toInstantiationType(Property p) { + if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + String inner = getSwaggerType(ap.getAdditionalProperties()); + return instantiationTypes.get("map"); + } + else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + return instantiationTypes.get("array"); + } + else + return null; + } + + @Override + public String getTypeDeclaration(String name) { + if(languageSpecificPrimitives.contains(name) && !foundationClasses.contains(name)) + return name; + else + return name + "*"; + } + + @Override + public String getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type) && !foundationClasses.contains(type)) + return toModelName(type); + } + else + type = swaggerType; + return toModelName(type); + } + + @Override + public String getTypeDeclaration(Property p) { + String swaggerType = getSwaggerType(p); + if(languageSpecificPrimitives.contains(swaggerType) && !foundationClasses.contains(swaggerType)) + return toModelName(swaggerType); + else + return swaggerType + "*"; + } + + @Override + public String toModelName(String type) { + if(typeMapping.keySet().contains(type) || + typeMapping.values().contains(type) || + foundationClasses.contains(type) || + importMapping.values().contains(type) || + defaultIncludes.contains(type) || + languageSpecificPrimitives.contains(type)) { + return type; + } + else { + return PREFIX + Character.toUpperCase(type.charAt(0)) + type.substring(1); + } + } + + @Override + public String toModelImport(String name) { + if(namespaces.containsKey(name)) { + return "using " + namespaces.get(name) + ";"; + } + return "#include \"" + name + ".h\""; + } + + @Override + public String toDefaultValue(Property p) { + if(p instanceof StringProperty) + return "new String()"; + else if (p instanceof BooleanProperty) + return "new Boolean(false)"; + else if(p instanceof DateProperty) + return "new DateTime()"; + else if(p instanceof DateTimeProperty) + return "new DateTime()"; + else if (p instanceof DoubleProperty) + return "new Double()"; + else if (p instanceof FloatProperty) + return "new Float()"; + else if (p instanceof IntegerProperty) + return "new Integer()"; + else if (p instanceof LongProperty) + return "new Long()"; + else if (p instanceof DecimalProperty) + return "new Long()"; + else if (p instanceof MapProperty) { + MapProperty ap = (MapProperty) p; + String inner = getSwaggerType(ap.getAdditionalProperties()); + return "new HashMap()"; + } + else if (p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + String inner = getSwaggerType(ap.getItems()); + return "new ArrayList()"; + } + // else + if(p instanceof RefProperty) { + RefProperty rp = (RefProperty) p; + return "new " + toModelName(rp.getSimpleRef()) + "()"; + } + return "null"; + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separator + sourceFolder; + } + + @Override + public String modelFileFolder() { + return outputFolder + File.separator + sourceFolder; + } + + @Override + public String toModelFilename(String name) { + return PREFIX + initialCaps(name); + } + + @Override + public String toApiName(String name) { + return PREFIX + initialCaps(name) + "Api"; + } + + public String toApiFilename(String name) { + return PREFIX + initialCaps(name) + "Api"; + } + + @Override + public String toVarName(String name) { + String paramName = name.replaceAll("[^a-zA-Z0-9_]",""); + paramName = Character.toUpperCase(paramName.charAt(0)) + paramName.substring(1); + return "p" + paramName; + } + + public String escapeReservedWord(String name) { + return "_" + name; + } +} diff --git a/modules/swagger-codegen/src/main/resources/Groovy/ApiUtils.mustache b/modules/swagger-codegen/src/main/resources/Groovy/ApiUtils.mustache new file mode 100644 index 00000000000..956b834c88c --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Groovy/ApiUtils.mustache @@ -0,0 +1,50 @@ +package {{invokerPackage}}; + +import groovyx.net.http.HTTPBuilder +import groovyx.net.http.Method + +import static groovyx.net.http.ContentType.JSON +import static java.net.URI.create; + +class ApiUtils { + + def invokeApi(onSuccess, onFailure, basePath, versionPath, resourcePath, queryParams, headerParams, method, container, type) { + def (url, uriPath) = buildUrlAndUriPath(basePath, versionPath, resourcePath) + println "url=$url uriPath=$uriPath" + def http = new HTTPBuilder(url) + http.request( Method.valueOf(method), JSON ) { + uri.path = uriPath + uri.query = queryParams + response.success = { resp, json -> + if (type != null) { + onSuccess(parse(json, container, type)) + } + } + response.failure = { resp -> + onFailure(resp.status, resp.statusLine.reasonPhrase) + } + } + } + + + def buildUrlAndUriPath(basePath, versionPath, resourcePath) { + // HTTPBuilder expects to get as its constructor parameter an URL, + // without any other additions like path, therefore we need to cut the path + // from the basePath as it is represented by swagger APIs + // we use java.net.URI to manipulate the basePath + // then the uriPath will hold the rest of the path + URI baseUri = create(basePath) + def pathOnly = baseUri.getPath() + [basePath-pathOnly, pathOnly+versionPath+resourcePath] + } + + + def parse(object, container, clazz) { + if (container == "List") { + return object.collect {parse(it, "", clazz)} + } else { + return clazz.newInstance(object) + } + } + +} diff --git a/modules/swagger-codegen/src/main/resources/Groovy/api.mustache b/modules/swagger-codegen/src/main/resources/Groovy/api.mustache new file mode 100644 index 00000000000..6ff66a84720 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Groovy/api.mustache @@ -0,0 +1,56 @@ +package {{package}}; + + + + + +import groovyx.net.http.* +import static groovyx.net.http.ContentType.* +import static groovyx.net.http.Method.* +import {{invokerPackage}}.ApiUtils +//------------- + +{{#imports}}import {{import}} +{{/imports}} + +import java.util.*; + +@Mixin(ApiUtils) +{{#operations}} +class {{classname}} { + String basePath = "{{basePath}}" + String versionPath = "/api/v1" + + + {{#operation}} + def {{nickname}} ({{#allParams}} {{{dataType}}} {{paramName}},{{/allParams}} Closure onSuccess, Closure onFailure) { + // create path and map variables + String resourcePath = "{{path}}" + + + // query params + def queryParams = [:] + def headerParams = [:] + + {{#requiredParamCount}} + // verify required params are set + if({{/requiredParamCount}}{{#requiredParams}} {{paramName}} == null {{#hasMore}}|| {{/hasMore}}{{/requiredParams}}{{#requiredParamCount}}) { + throw new RuntimeException("missing required params") + } + {{/requiredParamCount}} + + {{#queryParams}}if(!"null".equals(String.valueOf({{paramName}}))) + queryParams.put("{{paramName}}", String.valueOf({{paramName}})) + {{/queryParams}} + + {{#headerParams}}headerParams.put("{{paramName}}", {{paramName}}) + {{/headerParams}} + + invokeApi(onSuccess, onFailure, basePath, versionPath, resourcePath, queryParams, headerParams, + "{{httpMethod}}", "{{returnContainer}}", + {{#returnBaseType}}{{{returnBaseType}}}.class {{/returnBaseType}}{{^returnBaseType}}null {{/returnBaseType}}) + + } + {{/operation}} +} +{{/operations}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/Groovy/build.gradle.mustache b/modules/swagger-codegen/src/main/resources/Groovy/build.gradle.mustache new file mode 100644 index 00000000000..d98f375c61d --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Groovy/build.gradle.mustache @@ -0,0 +1,32 @@ +apply plugin: 'groovy' +apply plugin: 'idea' +def artifactory = 'buildserver.supportspace.com' +group = 'com.supportspace' +archivesBaseName = 'swagger-gen-groovy' +version = '0.1' + +buildscript { + repositories { + maven { url 'http://repo.jfrog.org/artifactory/gradle-plugins' } + } + dependencies { + classpath(group: 'org.jfrog.buildinfo', name: 'build-info-extractor-gradle', version: '2.0.16') + } +} + +repositories { + mavenCentral() + mavenLocal() + mavenCentral(artifactUrls: ['http://maven.springframework.org/milestone']) + maven { url "http://$artifactory:8080/artifactory/repo" } +} + +dependencies { + groovy "org.codehaus.groovy:groovy-all:2.0.5" + compile 'org.codehaus.groovy.modules.http-builder:http-builder:0.6' + + +} + +task wrapper(type: Wrapper) { gradleVersion = '1.6' } + diff --git a/modules/swagger-codegen/src/main/resources/Groovy/model.mustache b/modules/swagger-codegen/src/main/resources/Groovy/model.mustache new file mode 100644 index 00000000000..bc3ca28aaec --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Groovy/model.mustache @@ -0,0 +1,21 @@ +package {{package}}; + +import groovy.transform.Canonical +{{#imports}}import {{import}}; +{{/imports}} +{{#models}} +{{#model}} +@Canonical +class {{classname}} { + {{#vars}} + + {{#description}}/* {{{description}}} */ + {{/description}} + {{{datatype}}} {{name}} = {{{defaultValue}}} + {{/vars}} + + +} + +{{/model}} +{{/models}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/Java/JsonUtil.mustache b/modules/swagger-codegen/src/main/resources/Java/JsonUtil.mustache new file mode 100644 index 00000000000..29d5f55ecee --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Java/JsonUtil.mustache @@ -0,0 +1,23 @@ +package {{invokerPackage}}; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.core.JsonGenerator.Feature; + +import com.fasterxml.jackson.datatype.joda.*; + +public class JsonUtil { + public static ObjectMapper mapper; + + static { + mapper = new ObjectMapper(); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + mapper.registerModule(new JodaModule()); + } + + public static ObjectMapper getJsonMapper() { + return mapper; + } +} diff --git a/modules/swagger-codegen/src/main/resources/Java/api.mustache b/modules/swagger-codegen/src/main/resources/Java/api.mustache new file mode 100644 index 00000000000..c0a697e40b4 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Java/api.mustache @@ -0,0 +1,109 @@ +package {{package}}; + +import {{invokerPackage}}.ApiException; +import {{invokerPackage}}.ApiInvoker; + +import {{modelPackage}}.*; + +import java.util.*; + +{{#imports}}import {{import}}; +{{/imports}} + +import com.sun.jersey.multipart.FormDataMultiPart; + +import javax.ws.rs.core.MediaType; + +import java.io.File; +import java.util.Map; +import java.util.HashMap; + +{{#operations}} +public class {{classname}} { + String basePath = "{{basePath}}"; + ApiInvoker apiInvoker = ApiInvoker.getInstance(); + + public ApiInvoker getInvoker() { + return apiInvoker; + } + + public void setBasePath(String basePath) { + this.basePath = basePath; + } + + public String getBasePath() { + return basePath; + } + + {{#operation}} + {{#errorList}} //error info- code: {{code}} reason: "{{reason}}" model: {{#responseModel}}{{responseModel}} + {{/responseModel}}{{^responseModel}} + {{/responseModel}} + {{/errorList}} + public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{nickname}} ({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException { + Object postBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; + {{#requiredParamCount}} + // verify required params are set + if({{/requiredParamCount}}{{#requiredParams}} {{paramName}} == null {{#hasMore}}|| {{/hasMore}}{{/requiredParams}}{{#requiredParamCount}}) { + throw new ApiException(400, "missing required params"); + } + {{/requiredParamCount}} + + // create path and map variables + String path = "{{path}}".replaceAll("\\{format\\}","json"){{#pathParams}} + .replaceAll("\\{" + "{{paramName}}" + "\\}", apiInvoker.escapeString({{{paramName}}}.toString())){{/pathParams}}; + + // query params + Map queryParams = new HashMap(); + Map headerParams = new HashMap(); + Map formParams = new HashMap(); + + {{#queryParams}}if(!"null".equals(String.valueOf({{paramName}}))) + queryParams.put("{{baseName}}", String.valueOf({{paramName}})); + {{/queryParams}} + {{#headerParams}}headerParams.put("{{baseName}}", {{paramName}}); + {{/headerParams}} + String[] contentTypes = { + {{#consumes}}"{{mediaType}}"{{#hasMore}},{{/hasMore}}{{/consumes}} + }; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + + if(contentType.startsWith("multipart/form-data")) { + boolean hasFields = false; + FormDataMultiPart mp = new FormDataMultiPart(); + {{#formParams}}{{#notFile}} + hasFields = true; + mp.field("{{baseName}}", {{paramName}}, MediaType.MULTIPART_FORM_DATA_TYPE); + {{/notFile}}{{#isFile}} + hasFields = true; + mp.field("{{baseName}}", {{paramName}}, MediaType.MULTIPART_FORM_DATA_TYPE); + {{/isFile}}{{/formParams}} + if(hasFields) + postBody = mp; + } + else { + {{#formParams}}{{#notFile}}formParams.put("{{baseName}}", {{paramName}});{{/notFile}} + {{/formParams}} + } + + try { + String response = apiInvoker.invokeAPI(basePath, path, "{{httpMethod}}", queryParams, postBody, headerParams, formParams, contentType); + if(response != null){ + return {{#returnType}}({{{returnType}}}) ApiInvoker.deserialize(response, "{{returnContainer}}", {{returnBaseType}}.class){{/returnType}}; + } + else { + return {{#returnType}}null{{/returnType}}; + } + } catch (ApiException ex) { + if(ex.getCode() == 404) { + return {{#returnType}} null{{/returnType}}; + } + else { + throw ex; + } + } + } + {{/operation}} +} +{{/operations}} diff --git a/modules/swagger-codegen/src/main/resources/Java/apiException.mustache b/modules/swagger-codegen/src/main/resources/Java/apiException.mustache new file mode 100644 index 00000000000..a6bcba75b7c --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Java/apiException.mustache @@ -0,0 +1,29 @@ +package {{invokerPackage}}; + +public class ApiException extends Exception { + int code = 0; + String message = null; + + public ApiException() {} + + public ApiException(int code, String message) { + this.code = code; + this.message = message; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/Java/apiInvoker.mustache b/modules/swagger-codegen/src/main/resources/Java/apiInvoker.mustache new file mode 100644 index 00000000000..881cab13e12 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Java/apiInvoker.mustache @@ -0,0 +1,187 @@ +package {{invokerPackage}}; + +import com.fasterxml.jackson.core.JsonGenerator.Feature; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.config.ClientConfig; +import com.sun.jersey.api.client.config.DefaultClientConfig; +import com.sun.jersey.api.client.filter.LoggingFilter; +import com.sun.jersey.api.client.WebResource.Builder; +import com.sun.jersey.multipart.FormDataMultiPart; + +import javax.ws.rs.core.Response.Status.Family; +import javax.ws.rs.core.MediaType; + +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.io.IOException; +import java.net.URLEncoder; +import java.io.UnsupportedEncodingException; + +public class ApiInvoker { + private static ApiInvoker INSTANCE = new ApiInvoker(); + private Map hostMap = new HashMap(); + private Map defaultHeaderMap = new HashMap(); + private boolean isDebug = false; + + public void enableDebug() { + isDebug = true; + } + + public static ApiInvoker getInstance() { + return INSTANCE; + } + + public void addDefaultHeader(String key, String value) { + defaultHeaderMap.put(key, value); + } + + public String escapeString(String str) { + try{ + return URLEncoder.encode(str, "utf8").replaceAll("\\+", "%20"); + } + catch(UnsupportedEncodingException e) { + return str; + } + } + + public static Object deserialize(String json, String containerType, Class cls) throws ApiException { + try{ + if("List".equals(containerType)) { + JavaType typeInfo = JsonUtil.getJsonMapper().getTypeFactory().constructCollectionType(List.class, cls); + List response = (List) JsonUtil.getJsonMapper().readValue(json, typeInfo); + return response; + } + else if(String.class.equals(cls)) { + if(json != null && json.startsWith("\"") && json.endsWith("\"") && json.length() > 1) + return json.substring(1, json.length() - 2); + else + return json; + } + else { + return JsonUtil.getJsonMapper().readValue(json, cls); + } + } + catch (IOException e) { + throw new ApiException(500, e.getMessage()); + } + } + + public static String serialize(Object obj) throws ApiException { + try { + if (obj != null) + return JsonUtil.getJsonMapper().writeValueAsString(obj); + else + return null; + } + catch (Exception e) { + throw new ApiException(500, e.getMessage()); + } + } + + public String invokeAPI(String host, String path, String method, Map queryParams, Object body, Map headerParams, Map formParams, String contentType) throws ApiException { + Client client = getClient(host); + + StringBuilder b = new StringBuilder(); + + for(String key : queryParams.keySet()) { + String value = queryParams.get(key); + if (value != null){ + if(b.toString().length() == 0) + b.append("?"); + else + b.append("&"); + b.append(escapeString(key)).append("=").append(escapeString(value)); + } + } + String querystring = b.toString(); + + Builder builder = client.resource(host + path + querystring).accept("application/json"); + for(String key : headerParams.keySet()) { + builder.header(key, headerParams.get(key)); + } + + for(String key : defaultHeaderMap.keySet()) { + if(!headerParams.containsKey(key)) { + builder.header(key, defaultHeaderMap.get(key)); + } + } + ClientResponse response = null; + + if("GET".equals(method)) { + response = (ClientResponse) builder.get(ClientResponse.class); + } + else if ("POST".equals(method)) { + if(body == null) + response = builder.post(ClientResponse.class, null); + else if(body instanceof FormDataMultiPart) { + response = builder.type(contentType).post(ClientResponse.class, body); + } + else + response = builder.type(contentType).post(ClientResponse.class, serialize(body)); + } + else if ("PUT".equals(method)) { + if(body == null) + response = builder.put(ClientResponse.class, serialize(body)); + else { + if("application/x-www-form-urlencoded".equals(contentType)) { + StringBuilder formParamBuilder = new StringBuilder(); + + // encode the form params + for(String key : formParams.keySet()) { + String value = formParams.get(key); + if(value != null && !"".equals(value.trim())) { + if(formParamBuilder.length() > 0) { + formParamBuilder.append("&"); + } + try { + formParamBuilder.append(URLEncoder.encode(key, "utf8")).append("=").append(URLEncoder.encode(value, "utf8")); + } + catch (Exception e) { + // move on to next + } + } + } + response = builder.type(contentType).put(ClientResponse.class, formParamBuilder.toString()); + } + else + response = builder.type(contentType).put(ClientResponse.class, serialize(body)); + } + } + else if ("DELETE".equals(method)) { + if(body == null) + response = builder.delete(ClientResponse.class, serialize(body)); + else + response = builder.type(contentType).delete(ClientResponse.class, serialize(body)); + } + else { + throw new ApiException(500, "unknown method type " + method); + } + if(response.getClientResponseStatus() == ClientResponse.Status.NO_CONTENT) { + return null; + } + else if(response.getClientResponseStatus().getFamily() == Family.SUCCESSFUL) { + return (String) response.getEntity(String.class); + } + else { + throw new ApiException( + response.getClientResponseStatus().getStatusCode(), + response.getEntity(String.class)); + } + } + + private Client getClient(String host) { + if(!hostMap.containsKey(host)) { + Client client = Client.create(); + if(isDebug) + client.addFilter(new LoggingFilter()); + hostMap.put(host, client); + } + return hostMap.get(host); + } +} diff --git a/modules/swagger-codegen/src/main/resources/Java/model.mustache b/modules/swagger-codegen/src/main/resources/Java/model.mustache new file mode 100644 index 00000000000..60aa5d72a35 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Java/model.mustache @@ -0,0 +1,49 @@ +package {{package}}; + +{{#imports}}import {{import}}; +{{/imports}} + +import com.wordnik.swagger.annotations.*; +import com.fasterxml.jackson.annotation.JsonProperty; +{{#models}} + +{{#model}}{{#description}} +/** + * {{description}} + **/{{/description}} +@ApiModel(description = "{{{description}}}") +public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} { {{#vars}} + private {{{datatype}}} {{name}} = {{{defaultValue}}};{{#allowableValues}} + + //{{^min}}public enum {{name}}Enum { {{#values}} {{.}}, {{/values}} }; + {{/min}}{{/allowableValues}}{{/vars}} + + {{#vars}} + /**{{#description}} + * {{{description}}}{{/description}}{{#minimum}} + * minimum: {{minimum}}{{/minimum}}{{#maximum}} + * maximum: {{maximum}}{{/maximum}} + **/ + @ApiModelProperty(required = {{required}}, value = "{{{description}}}") + @JsonProperty("{{name}}") + public {{{datatype}}} {{getter}}() { + return {{name}}; + } + public void {{setter}}({{{datatype}}} {{name}}) { + this.{{name}} = {{name}}; + } + + {{/vars}} + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class {{classname}} {\n"); + {{#parent}}sb.append(" " + super.toString()).append("\n");{{/parent}} + {{#vars}}sb.append(" {{name}}: ").append({{name}}).append("\n"); + {{/vars}}sb.append("}\n"); + return sb.toString(); + } +} +{{/model}} +{{/models}} diff --git a/modules/swagger-codegen/src/main/resources/Java/pom.mustache b/modules/swagger-codegen/src/main/resources/Java/pom.mustache new file mode 100644 index 00000000000..73d62103e22 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Java/pom.mustache @@ -0,0 +1,168 @@ + + 4.0.0 + {{groupId}} + {{artifactId}} + jar + {{artifactId}} + {{artifactVersion}} + + scm:git:git@github.com:wordnik/swagger-mustache.git + scm:git:git@github.com:wordnik/swagger-codegen.git + https://github.com/wordnik/swagger-codegen + + + 2.2.0 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12 + + + + loggerPath + conf/log4j.properties + + + -Xms512m -Xmx1500m + methods + pertest + + + + maven-dependency-plugin + + + package + + copy-dependencies + + + ${project.build.directory}/lib + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.2 + + + + jar + test-jar + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add_sources + generate-sources + + add-source + + + + src/main/java + + + + + add_test_sources + generate-test-sources + + add-test-source + + + + src/test/java + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.6 + 1.6 + + + + + + + com.wordnik + swagger-annotations + ${swagger-annotations-version} + + + com.sun.jersey + jersey-client + ${jersey-version} + + + com.sun.jersey.contribs + jersey-multipart + ${jersey-version} + + + com.fasterxml.jackson.core + jackson-core + ${jackson-version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson-version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson-version} + + + com.fasterxml.jackson.datatype + jackson-datatype-joda + 2.1.5 + + + joda-time + joda-time + ${jodatime-version} + + + + + junit + junit + ${junit-version} + test + + + + 1.5.0-M1 + 1.7 + 2.1.4 + 2.3 + 4.8.1 + 1.0.0 + 4.8.1 + + diff --git a/modules/swagger-codegen/src/main/resources/JavaJaxRS/ApiException.mustache b/modules/swagger-codegen/src/main/resources/JavaJaxRS/ApiException.mustache new file mode 100644 index 00000000000..ffab3b1088e --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JavaJaxRS/ApiException.mustache @@ -0,0 +1,9 @@ +package {{apiPackage}}; + +public class ApiException extends Exception{ + private int code; + public ApiException (int code, String msg) { + super(msg); + this.code = code; + } +} diff --git a/modules/swagger-codegen/src/main/resources/JavaJaxRS/ApiOriginFilter.mustache b/modules/swagger-codegen/src/main/resources/JavaJaxRS/ApiOriginFilter.mustache new file mode 100644 index 00000000000..68675432c64 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JavaJaxRS/ApiOriginFilter.mustache @@ -0,0 +1,26 @@ +package {{apiPackage}}; + +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 { + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/JavaJaxRS/ApiResponseMessage.mustache b/modules/swagger-codegen/src/main/resources/JavaJaxRS/ApiResponseMessage.mustache new file mode 100644 index 00000000000..94711b26efb --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JavaJaxRS/ApiResponseMessage.mustache @@ -0,0 +1,68 @@ +package {{apiPackage}}; + +import javax.xml.bind.annotation.XmlTransient; + +@javax.xml.bind.annotation.XmlRootElement +public class ApiResponseMessage { + 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 ApiResponseMessage(){} + + public ApiResponseMessage(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; + } +} diff --git a/modules/swagger-codegen/src/main/resources/JavaJaxRS/NotFoundException.mustache b/modules/swagger-codegen/src/main/resources/JavaJaxRS/NotFoundException.mustache new file mode 100644 index 00000000000..8ab2c99e4f8 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JavaJaxRS/NotFoundException.mustache @@ -0,0 +1,9 @@ +package {{apiPackage}}; + +public class NotFoundException extends ApiException { + private int code; + public NotFoundException (int code, String msg) { + super(code, msg); + this.code = code; + } +} diff --git a/modules/swagger-codegen/src/main/resources/JavaJaxRS/README.mustache b/modules/swagger-codegen/src/main/resources/JavaJaxRS/README.mustache new file mode 100644 index 00000000000..f8a560b776f --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JavaJaxRS/README.mustache @@ -0,0 +1,10 @@ +# Swagger generated server + +## Overview +This server was generated by the [swagger-codegen](https://github.com/wordnik/swagger-codegen) project. By using the +[swagger-spec](https://github.com/wordnik/swagger-core/wiki) from a remote server, you can easily generate a server stub. This +is an example of building a swagger-enabled scalatra server. + +This example uses the [scalatra](http://scalatra.org/) framework. To see how to make this your own, look here: + +[README](https://github.com/wordnik/swagger-codegen/tree/master/samples/server-generator/scalatra) \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/JavaJaxRS/api.mustache b/modules/swagger-codegen/src/main/resources/JavaJaxRS/api.mustache new file mode 100644 index 00000000000..fe287c9ddfe --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JavaJaxRS/api.mustache @@ -0,0 +1,40 @@ +package {{package}}; + +import {{modelPackage}}.*; + +import com.wordnik.swagger.annotations.*; +import com.sun.jersey.multipart.FormDataParam; + +{{#imports}}import {{import}}; +{{/imports}} + +import java.util.List; +import {{package}}.NotFoundException; + +import javax.ws.rs.core.Response; +import javax.ws.rs.*; + +@Path("/{{baseName}}") +@Api(value = "/{{baseName}}", description = "the {{baseName}} API") +{{#operations}} +public class {{classname}} { + {{#operation}} + @{{httpMethod}} + {{#subresourceOperation}}@Path("{{path}}"){{/subresourceOperation}} + {{#hasConsumes}}@Consumes({ {{#consumes}}"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} }){{/hasConsumes}} + {{#hasProduces}}@Produces({ {{#produces}}"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/produces}} }){{/hasProduces}} + @ApiOperation(value = "{{{summary}}}", notes = "{{{notes}}}", response = {{{returnType}}}.class{{#returnContainer}}, responseContainer = "{{{returnContainer}}}"{{/returnContainer}}) + @ApiResponses(value = { {{#responses}} + @ApiResponse(code = {{{code}}}, message = "{{{message}}}"){{#hasMore}}, + {{/hasMore}}{{/responses}} }) + + public Response {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}}, + {{/hasMore}}{{/allParams}}) + throws NotFoundException { + // do some magic! + return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build(); + } + + {{/operation}} +} +{{/operations}} diff --git a/modules/swagger-codegen/src/main/resources/JavaJaxRS/bodyParams.mustache b/modules/swagger-codegen/src/main/resources/JavaJaxRS/bodyParams.mustache new file mode 100644 index 00000000000..86546afb9ca --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JavaJaxRS/bodyParams.mustache @@ -0,0 +1 @@ +{{#isBodyParam}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}} {{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{{dataType}}} {{paramName}}{{/isBodyParam}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/JavaJaxRS/formParams.mustache b/modules/swagger-codegen/src/main/resources/JavaJaxRS/formParams.mustache new file mode 100644 index 00000000000..46076485aa9 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JavaJaxRS/formParams.mustache @@ -0,0 +1 @@ +{{#isFormParam}}{{#notFile}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}} {{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@FormParam("{{paramName}}") {{{dataType}}} {{paramName}}{{/notFile}}{{#isFile}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}} {{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@FormDataParam("{{paramName}}") {{{dataType}}} {{paramName}}{{/isFile}}{{/isFormParam}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/JavaJaxRS/headerParams.mustache b/modules/swagger-codegen/src/main/resources/JavaJaxRS/headerParams.mustache new file mode 100644 index 00000000000..0f88692ad1d --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JavaJaxRS/headerParams.mustache @@ -0,0 +1 @@ +{{#isHeaderParam}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}} {{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@HeaderParam("{{paramName}}") {{{dataType}}} {{paramName}}{{/isHeaderParam}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/JavaJaxRS/model.mustache b/modules/swagger-codegen/src/main/resources/JavaJaxRS/model.mustache new file mode 100644 index 00000000000..f6cb2b01cdf --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JavaJaxRS/model.mustache @@ -0,0 +1,47 @@ +package {{package}}; + +{{#imports}}import {{import}}; +{{/imports}} + +import com.wordnik.swagger.annotations.*; +{{#models}} + +{{#model}}{{#description}} +/** + * {{description}} + **/{{/description}} +@ApiModel(description = "{{{description}}}") +public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} { {{#vars}} + /**{{#description}} + * {{{description}}}{{/description}}{{#minimum}} + * minimum: {{minimum}}{{/minimum}}{{#maximum}} + * maximum: {{maximum}}{{/maximum}} + **/ + private {{{datatype}}} {{name}} = {{{defaultValue}}};{{#isEnum}} + + public enum {{datatype}} { {{#_enum}}{{.}}{{^-last}}, {{/-last}}{{/_enum}} }; + {{/isEnum}}{{/vars}} + + {{#vars}} + @ApiModelProperty(required = {{required}}, value = "{{{description}}}") + public {{{datatype}}} {{getter}}() { + return {{name}}; + } + public void {{setter}}({{{datatype}}} {{name}}) { + this.{{name}} = {{name}}; + } + + {{/vars}} + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class {{classname}} {\n"); + {{#parent}}sb.append(" " + super.toString()).append("\n");{{/parent}} + {{#vars}}sb.append(" {{name}}: ").append({{name}}).append("\n"); + {{/vars}}sb.append("}\n"); + return sb.toString(); + } +} +{{/model}} +{{/models}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/JavaJaxRS/pathParams.mustache b/modules/swagger-codegen/src/main/resources/JavaJaxRS/pathParams.mustache new file mode 100644 index 00000000000..1f1b30887a4 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JavaJaxRS/pathParams.mustache @@ -0,0 +1 @@ +{{#isPathParam}}@ApiParam(value = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}} {{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @PathParam("{{paramName}}") {{{dataType}}} {{paramName}}{{/isPathParam}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/JavaJaxRS/pom.mustache b/modules/swagger-codegen/src/main/resources/JavaJaxRS/pom.mustache new file mode 100644 index 00000000000..e0782610efd --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JavaJaxRS/pom.mustache @@ -0,0 +1,141 @@ + + 4.0.0 + {{groupId}} + {{artifactId}} + jar + {{artifactId}} + {{artifactVersion}} + + src/main/java + + + org.apache.maven.plugins + maven-war-plugin + 2.1.1 + + + maven-failsafe-plugin + 2.6 + + + + integration-test + verify + + + + + + org.mortbay.jetty + jetty-maven-plugin + ${jetty-version} + + + {{^basePath}}/{{/basePath}}{{#basePath}}{{basePath}}{{/basePath}} + + target/${project.artifactId}-${project.version} + ${project.basedir}/conf/jetty/webdefault.xml + 8079 + stopit + + + 8002 + 60000 + 8443 + + + + + + start-jetty + pre-integration-test + + run + + + 0 + true + + + + stop-jetty + post-integration-test + + stop + + + + + + + + + com.wordnik + swagger-jersey-jaxrs + ${swagger-core-version} + + + org.slf4j + slf4j-log4j12 + ${slf4j-version} + + + com.sun.jersey + jersey-core + ${jersey-version} + + + com.sun.jersey + jersey-json + ${jersey-version} + + + com.sun.jersey + jersey-servlet + ${jersey-version} + + + com.sun.jersey.contribs + jersey-multipart + ${jersey-version} + + + com.sun.jersey + jersey-server + ${jersey-version} + + + + org.scalatest + scalatest_2.9.1 + ${scala-test-version} + test + + + junit + junit + ${junit-version} + test + + + javax.servlet + servlet-api + ${servlet-api-version} + + + + + sonatype-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + + + 1.5.0-SNAPSHOT + 8.1.11.v20130520 + 1.13 + 1.6.3 + 1.6.1 + 4.8.1 + 2.5 + + \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/JavaJaxRS/project/build.properties b/modules/swagger-codegen/src/main/resources/JavaJaxRS/project/build.properties new file mode 100644 index 00000000000..a8c2f849be3 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JavaJaxRS/project/build.properties @@ -0,0 +1 @@ +sbt.version=0.12.0 diff --git a/modules/swagger-codegen/src/main/resources/JavaJaxRS/project/plugins.sbt b/modules/swagger-codegen/src/main/resources/JavaJaxRS/project/plugins.sbt new file mode 100644 index 00000000000..713b7f3e993 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JavaJaxRS/project/plugins.sbt @@ -0,0 +1,9 @@ +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.8.4") + +libraryDependencies <+= sbtVersion(v => v match { + case "0.11.0" => "com.github.siasia" %% "xsbt-web-plugin" % "0.11.0-0.2.8" + case "0.11.1" => "com.github.siasia" %% "xsbt-web-plugin" % "0.11.1-0.2.10" + case "0.11.2" => "com.github.siasia" %% "xsbt-web-plugin" % "0.11.2-0.2.11" + case "0.11.3" => "com.github.siasia" %% "xsbt-web-plugin" % "0.11.3-0.2.11.1" + case x if (x.startsWith("0.12")) => "com.github.siasia" %% "xsbt-web-plugin" % "0.12.0-0.2.11.1" +}) \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/JavaJaxRS/queryParams.mustache b/modules/swagger-codegen/src/main/resources/JavaJaxRS/queryParams.mustache new file mode 100644 index 00000000000..b9e80e5a7e7 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JavaJaxRS/queryParams.mustache @@ -0,0 +1 @@ +{{#isQueryParam}}@ApiParam(value = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @QueryParam("{{paramName}}") {{{dataType}}} {{paramName}}{{/isQueryParam}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/JavaJaxRS/web.mustache b/modules/swagger-codegen/src/main/resources/JavaJaxRS/web.mustache new file mode 100644 index 00000000000..b9cd00b71ce --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JavaJaxRS/web.mustache @@ -0,0 +1,54 @@ + + + + + jersey + com.sun.jersey.spi.container.servlet.ServletContainer + + com.sun.jersey.config.property.packages + com.wordnik.swagger.jaxrs.json;com.wordnik.swagger.jaxrs.listing;{{apiPackage}} + + + com.sun.jersey.spi.container.ContainerRequestFilters + com.sun.jersey.api.container.filter.PostReplaceFilter + + + com.sun.jersey.api.json.POJOMappingFeature + true + + 1 + + + + DefaultJaxrsConfig + com.wordnik.swagger.jaxrs.config.DefaultJaxrsConfig + + api.version + 1.0.0 + + + swagger.api.title + {{{title}}} + + + swagger.api.basepath + http://localhost:8002 + + 2 + + + + jersey + /* + + + ApiOriginFilter + com.wordnik.api.ApiOriginFilter + + + ApiOriginFilter + /* + + diff --git a/modules/swagger-codegen/src/main/resources/META-INF/services/com.wordnik.swagger.codegen.CodegenConfig b/modules/swagger-codegen/src/main/resources/META-INF/services/com.wordnik.swagger.codegen.CodegenConfig new file mode 100644 index 00000000000..3f8102a750d --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/META-INF/services/com.wordnik.swagger.codegen.CodegenConfig @@ -0,0 +1,13 @@ +com.wordnik.swagger.codegen.languages.AndroidClientCodegen +com.wordnik.swagger.codegen.languages.JavaClientCodegen +com.wordnik.swagger.codegen.languages.JaxRSServerCodegen +com.wordnik.swagger.codegen.languages.NodeJSServerCodegen +com.wordnik.swagger.codegen.languages.ObjcClientCodegen +com.wordnik.swagger.codegen.languages.ScalatraServerCodegen +com.wordnik.swagger.codegen.languages.ScalaClientCodegen +com.wordnik.swagger.codegen.languages.StaticDocCodegen +com.wordnik.swagger.codegen.languages.StaticHtmlGenerator +com.wordnik.swagger.codegen.languages.SwaggerGenerator +com.wordnik.swagger.codegen.languages.TizenClientCodegen +com.wordnik.swagger.codegen.languages.PhpClientCodegen +com.wordnik.swagger.codegen.languages.PythonClientCodegen \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/android-java/api.mustache b/modules/swagger-codegen/src/main/resources/android-java/api.mustache new file mode 100644 index 00000000000..1eab419d31a --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/android-java/api.mustache @@ -0,0 +1,88 @@ +package {{package}}; + +import {{invokerPackage}}.ApiException; +import {{invokerPackage}}.ApiInvoker; + +import {{modelPackage}}.*; + +import java.util.*; + +{{#imports}}import {{import}}; +{{/imports}} + +import java.util.Map; +import java.util.HashMap; +import java.io.File; + +{{#operations}} +public class {{classname}} { + String basePath = "{{basePath}}"; + ApiInvoker apiInvoker = ApiInvoker.getInstance(); + + public void addHeader(String key, String value) { + getInvoker().addDefaultHeader(key, value); + } + + public ApiInvoker getInvoker() { + return apiInvoker; + } + + public void setBasePath(String basePath) { + this.basePath = basePath; + } + + public String getBasePath() { + return basePath; + } + + {{#operation}} + {{#errorList}} //error info- code: {{code}} reason: "{{reason}}" model: {{#responseModel}}{{responseModel}} + {{/responseModel}}{{^responseModel}} + {{/responseModel}} + {{/errorList}} + public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}} {{nickname}} ({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException { + Object postBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; + + {{#requiredParamCount}} + // verify required params are set + if({{/requiredParamCount}}{{#requiredParams}} {{paramName}} == null {{#hasMore}}|| {{/hasMore}}{{/requiredParams}}{{#requiredParamCount}}) { + throw new ApiException(400, "missing required params"); + } + {{/requiredParamCount}} + + // create path and map variables + String path = "{{path}}".replaceAll("\\{format\\}","json"){{#pathParams}}.replaceAll("\\{" + "{{paramName}}" + "\\}", apiInvoker.escapeString({{{paramName}}}.toString())){{/pathParams}}; + + // query params + Map queryParams = new HashMap(); + Map headerParams = new HashMap(); + + {{#queryParams}}if(!"null".equals(String.valueOf({{paramName}}))) + queryParams.put("{{baseName}}", String.valueOf({{paramName}})); + {{/queryParams}} + + {{#headerParams}}headerParams.put("{{baseName}}", {{paramName}}); + {{/headerParams}} + + String contentType = "application/json"; + + try { + String response = apiInvoker.invokeAPI(basePath, path, "{{httpMethod}}", queryParams, postBody, headerParams, contentType); + if(response != null){ + return {{#returnType}}({{{returnType}}}) ApiInvoker.deserialize(response, "{{returnContainer}}", {{returnBaseType}}.class){{/returnType}}; + } + else { + return {{#returnType}}null{{/returnType}}; + } + } catch (ApiException ex) { + if(ex.getCode() == 404) { + return {{#returnType}} null{{/returnType}}; + } + else { + throw ex; + } + } + } + {{/operation}} +} +{{/operations}} diff --git a/modules/swagger-codegen/src/main/resources/android-java/apiException.mustache b/modules/swagger-codegen/src/main/resources/android-java/apiException.mustache new file mode 100644 index 00000000000..a6bcba75b7c --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/android-java/apiException.mustache @@ -0,0 +1,29 @@ +package {{invokerPackage}}; + +public class ApiException extends Exception { + int code = 0; + String message = null; + + public ApiException() {} + + public ApiException(int code, String message) { + this.code = code; + this.message = message; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/android-java/apiInvoker.mustache b/modules/swagger-codegen/src/main/resources/android-java/apiInvoker.mustache new file mode 100644 index 00000000000..425c2e7e004 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/android-java/apiInvoker.mustache @@ -0,0 +1,283 @@ +package {{invokerPackage}}; + + +import com.fasterxml.jackson.core.JsonGenerator.Feature; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +import org.apache.http.*; +import org.apache.http.client.*; +import org.apache.http.client.methods.*; +import org.apache.http.conn.*; +import org.apache.http.conn.scheme.*; +import org.apache.http.conn.ssl.*; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.*; +import org.apache.http.impl.conn.*; +import org.apache.http.params.*; +import org.apache.http.util.EntityUtils; + +import java.io.File; +import java.net.Socket; +import java.net.UnknownHostException; +import java.net.URLEncoder; + +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +import java.security.GeneralSecurityException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.*; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +import java.util.Date; +import java.util.Random; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +public class ApiInvoker { + private static ApiInvoker INSTANCE = new ApiInvoker(); + private Map defaultHeaderMap = new HashMap(); + + private HttpClient client = null; + + private boolean ignoreSSLCertificates = false; + + private ClientConnectionManager ignoreSSLConnectionManager; + + public ApiInvoker() { + initConnectionManager(); + } + + public static ApiInvoker getInstance() { + return INSTANCE; + } + + public void ignoreSSLCertificates(boolean ignoreSSLCertificates) { + this.ignoreSSLCertificates = ignoreSSLCertificates; + } + + public void addDefaultHeader(String key, String value) { + defaultHeaderMap.put(key, value); + } + + public String escapeString(String str) { + return str; + } + + public static Object deserialize(String json, String containerType, Class cls) throws ApiException { + try{ + if("List".equals(containerType)) { + JavaType typeInfo = JsonUtil.getJsonMapper().getTypeFactory().constructCollectionType(List.class, cls); + List response = (List) JsonUtil.getJsonMapper().readValue(json, typeInfo); + return response; + } + else if(String.class.equals(cls)) { + if(json != null && json.startsWith("\"") && json.endsWith("\"") && json.length() > 1) + return json.substring(1, json.length() - 2); + else + return json; + } + else { + return JsonUtil.getJsonMapper().readValue(json, cls); + } + } + catch (IOException e) { + throw new ApiException(500, e.getMessage()); + } + } + + public static String serialize(Object obj) throws ApiException { + try { + if (obj != null) + return JsonUtil.getJsonMapper().writeValueAsString(obj); + else + return null; + } + catch (Exception e) { + throw new ApiException(500, e.getMessage()); + } + } + + public String invokeAPI(String host, String path, String method, Map queryParams, Object body, Map headerParams, String contentType) throws ApiException { + HttpClient client = getClient(host); + + StringBuilder b = new StringBuilder(); + for(String key : queryParams.keySet()) { + String value = queryParams.get(key); + if (value != null){ + if(b.toString().length() == 0) + b.append("?"); + else + b.append("&"); + b.append(escapeString(key)).append("=").append(escapeString(value)); + } + } + String url = host + path + b.toString(); + + HashMap headers = new HashMap(); + + for(String key : headerParams.keySet()) { + headers.put(key, headerParams.get(key)); + } + + for(String key : defaultHeaderMap.keySet()) { + if(!headerParams.containsKey(key)) { + headers.put(key, defaultHeaderMap.get(key)); + } + } + headers.put("Accept", "application/json"); + + HttpResponse response = null; + try{ + if("GET".equals(method)) { + HttpGet get = new HttpGet(url); + get.addHeader("Accept", "application/json"); + for(String key : headers.keySet()) { + get.setHeader(key, headers.get(key)); + } + response = client.execute(get); + } + else if ("POST".equals(method)) { + HttpPost post = new HttpPost(url); + + if (body != null) { + post.setHeader("Content-Type", contentType); + post.setEntity(new StringEntity(serialize(body), "UTF-8")); + } + for(String key : headers.keySet()) { + post.setHeader(key, headers.get(key)); + } + response = client.execute(post); + } + else if ("PUT".equals(method)) { + HttpPut put = new HttpPut(url); + if(body != null) { + put.setHeader("Content-Type", contentType); + put.setEntity(new StringEntity(serialize(body), "UTF-8")); + } + for(String key : headers.keySet()) { + put.setHeader(key, headers.get(key)); + } + response = client.execute(put); + } + else if ("DELETE".equals(method)) { + HttpDelete delete = new HttpDelete(url); + for(String key : headers.keySet()) { + delete.setHeader(key, headers.get(key)); + } + response = client.execute(delete); + } + else if ("PATCH".equals(method)) { + HttpPatch patch = new HttpPatch(url); + + if (body != null) { + patch.setHeader("Content-Type", contentType); + patch.setEntity(new StringEntity(serialize(body), "UTF-8")); + } + for(String key : headers.keySet()) { + patch.setHeader(key, headers.get(key)); + } + response = client.execute(patch); + } + + int code = response.getStatusLine().getStatusCode(); + String responseString = null; + if(code == 204) + responseString = ""; + else if(code >= 200 && code < 300) { + if(response.getEntity() != null) { + HttpEntity resEntity = response.getEntity(); + responseString = EntityUtils.toString(resEntity); + } + } + else { + if(response.getEntity() != null) { + HttpEntity resEntity = response.getEntity(); + responseString = EntityUtils.toString(resEntity); + } + else + responseString = "no data"; + throw new ApiException(code, responseString); + } + return responseString; + } + catch(IOException e) { + throw new ApiException(500, e.getMessage()); + } + } + + private HttpClient getClient(String host) { + if (client == null) { + if (ignoreSSLCertificates && ignoreSSLConnectionManager != null) { + // Trust self signed certificates + client = new DefaultHttpClient(ignoreSSLConnectionManager, new BasicHttpParams()); + } else { + client = new DefaultHttpClient(); + } + } + return client; + } + + private void initConnectionManager() { + try { + final SSLContext sslContext = SSLContext.getInstance("SSL"); + + // set up a TrustManager that trusts everything + TrustManager[] trustManagers = new TrustManager[] { + new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + public void checkClientTrusted(X509Certificate[] certs, String authType) {} + public void checkServerTrusted(X509Certificate[] certs, String authType) {} + }}; + + sslContext.init(null, trustManagers, new SecureRandom()); + + SSLSocketFactory sf = new SSLSocketFactory((KeyStore)null) { + private javax.net.ssl.SSLSocketFactory sslFactory = sslContext.getSocketFactory(); + + public Socket createSocket(Socket socket, String host, int port, boolean autoClose) + throws IOException, UnknownHostException { + return sslFactory.createSocket(socket, host, port, autoClose); + } + + public Socket createSocket() throws IOException { + return sslFactory.createSocket(); + } + }; + + sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + Scheme httpsScheme = new Scheme("https", sf, 443); + SchemeRegistry schemeRegistry = new SchemeRegistry(); + schemeRegistry.register(httpsScheme); + schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); + + ignoreSSLConnectionManager = new SingleClientConnManager(new BasicHttpParams(), schemeRegistry); + } catch (NoSuchAlgorithmException e) { + // This will only be thrown if SSL isn't available for some reason. + } catch (KeyManagementException e) { + // This might be thrown when passing a key into init(), but no key is being passed. + } catch (GeneralSecurityException e) { + // This catches anything else that might go wrong. + // If anything goes wrong we default to the standard connection manager. + } + } +} diff --git a/modules/swagger-codegen/src/main/resources/android-java/httpPatch.mustache b/modules/swagger-codegen/src/main/resources/android-java/httpPatch.mustache new file mode 100644 index 00000000000..55cec2f1279 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/android-java/httpPatch.mustache @@ -0,0 +1,16 @@ +package {{invokerPackage}}; + +import org.apache.http.client.methods.*; + +public class HttpPatch extends HttpPost { + public static final String METHOD_PATCH = "PATCH"; + + public HttpPatch(final String url) { + super(url); + } + + @Override + public String getMethod() { + return METHOD_PATCH; + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/android-java/jsonUtil.mustache b/modules/swagger-codegen/src/main/resources/android-java/jsonUtil.mustache new file mode 100644 index 00000000000..ef00838c17f --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/android-java/jsonUtil.mustache @@ -0,0 +1,20 @@ +package {{invokerPackage}}; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.core.JsonGenerator.Feature; + +public class JsonUtil { + public static ObjectMapper mapper; + + static { + mapper = new ObjectMapper(); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + } + + public static ObjectMapper getJsonMapper() { + return mapper; + } +} diff --git a/modules/swagger-codegen/src/main/resources/android-java/model.mustache b/modules/swagger-codegen/src/main/resources/android-java/model.mustache new file mode 100644 index 00000000000..0d60aedd068 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/android-java/model.mustache @@ -0,0 +1,47 @@ +package {{package}}; + +{{#imports}}import {{import}}; +{{/imports}} + +import com.wordnik.swagger.annotations.*; +{{#models}} + +{{#model}}{{#description}} +/** + * {{description}} + **/{{/description}} +@ApiModel(description = "{{{description}}}") +public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} { {{#vars}} + private {{{datatype}}} {{name}} = {{{defaultValue}}};{{#allowableValues}} + + //{{^min}}public enum {{name}}Enum { {{#values}} {{.}}, {{/values}} }; + {{/min}}{{/allowableValues}}{{/vars}} + + {{#vars}} + /**{{#description}} + * {{{description}}}{{/description}}{{#minimum}} + * minimum: {{minimum}}{{/minimum}}{{#maximum}} + * maximum: {{maximum}}{{/maximum}} + **/ + @ApiModelProperty(required = {{required}}, value = "{{{description}}}") + public {{{datatype}}} {{getter}}() { + return {{name}}; + } + public void {{setter}}({{{datatype}}} {{name}}) { + this.{{name}} = {{name}}; + } + + {{/vars}} + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class {{classname}} {\n"); + {{#parent}}sb.append(" " + super.toString()).append("\n");{{/parent}} + {{#vars}}sb.append(" {{name}}: ").append({{name}}).append("\n"); + {{/vars}}sb.append("}\n"); + return sb.toString(); + } +} +{{/model}} +{{/models}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/android-java/pom.mustache b/modules/swagger-codegen/src/main/resources/android-java/pom.mustache new file mode 100644 index 00000000000..11641082eee --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/android-java/pom.mustache @@ -0,0 +1,162 @@ + + 4.0.0 + {{groupId}} + {{artifactId}} + jar + {{artifactId}} + {{artifactVersion}} + + scm:git:git@github.com:wordnik/swagger-mustache.git + scm:git:git@github.com:wordnik/swagger-codegen.git + https://github.com/wordnik/swagger-codegen + + + 2.2.0 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12 + + + + loggerPath + conf/log4j.properties + + + -Xms512m -Xmx1500m + methods + pertest + + + + maven-dependency-plugin + + + package + + copy-dependencies + + + ${project.build.directory}/lib + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.2 + + + + jar + test-jar + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add_sources + generate-sources + + add-source + + + + src/main/java + + + + + add_test_sources + generate-test-sources + + add-test-source + + + + src/test/java + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.6 + 1.6 + + + + + + + com.wordnik + swagger-annotations + ${swagger-annotations-version} + + + com.fasterxml.jackson.core + jackson-core + ${jackson-version} + compile + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson-version} + compile + + + com.fasterxml.jackson.core + jackson-databind + ${jackson-version} + compile + + + org.apache.httpcomponents + httpclient + ${httpclient-version} + compile + + + + + junit + junit + ${junit-version} + test + + + + + sonatype-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + + + 1.5.0-SNAPSHOT + 2.1.4 + 4.8.1 + 1.0.0 + 4.8.1 + 4.0 + + diff --git a/modules/swagger-codegen/src/main/resources/asyncscala/api.mustache b/modules/swagger-codegen/src/main/resources/asyncscala/api.mustache new file mode 100644 index 00000000000..2a8664450d5 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/asyncscala/api.mustache @@ -0,0 +1,59 @@ +package {{package}} + +{{#imports}}import {{import}} +{{/imports}} +import com.wordnik.swagger.client._ +import scala.concurrent.{ Future, Await } +import scala.concurrent.duration._ +import collection.mutable + +{{#operations}} +class {{className}}(client: TransportClient, config: SwaggerConfig) extends ApiClient(client, config) { + + {{#operation}} + + def {{nickname}}({{#allParams}} + {{#optional}} + {{paramName}}: Option[{{dataType}}] = {{#defaultValue}}Some({{defaultValue}}){{/defaultValue}}{{^defaultValue}}None{{/defaultValue}}{{#hasMore}}, {{/hasMore}} + {{/optional}} + {{^optional}} + {{paramName}}: {{dataType}}{{#defaultValue}} = {{{defaultValue}}}{{/defaultValue}}{{#hasMore}}, {{/hasMore}} + {{/optional}}{{/allParams}})(implicit reader: ClientResponseReader[{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Unit{{/returnType}}]{{#bodyParams}}, writer: RequestWriter[{{dataType}}]{{/bodyParams}}){{#returnType}}: Future[{{returnType}}]{{/returnType}}{{^returnType}}: Future[Unit]{{/returnType}} = { + // create path and map variables + val path = + (addFmt("{{path}}"){{#pathParams}} + replaceAll ("\\{" + "{{baseName}}" + "\\}",{{paramName}}.toString) + {{/pathParams}}) + + // query params + val queryParams = new mutable.HashMap[String, String] + val headerParams = new mutable.HashMap[String, String] + + {{#requiredParamCount}} + // verify required params are set + val paramCount = (Set[Any]({{/requiredParamCount}}{{#requiredParams}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/requiredParams}}{{#requiredParamCount}}) - null).size + if (paramCount != {{requiredParamCount}}) sys.error("missing required params") + {{/requiredParamCount}} + + {{#queryParams}} + {{#optional}} + if({{paramName}} != null) {{paramName}}.foreach { v => queryParams += "{{baseName}}" -> v.toString } + {{/optional}} + {{^optional}} + if({{paramName}} != null) queryParams += "{{baseName}}" -> {{paramName}}.toString + {{/optional}} + {{/queryParams}} + + {{#headerParams}}headerParams += "{{baseName}}" -> {{paramName}}.toString + {{/headerParams}} + + val resFuture = client.submit("{{httpMethod}}", path, queryParams.toMap, headerParams.toMap, {{#bodyParam}}writer.write({{bodyParam}}){{/bodyParam}}{{^bodyParam}}"{{emptyBodyParam}}"{{/bodyParam}}) + resFuture flatMap { resp => + process(reader.read(resp)) + } + } + + {{/operation}} + +} +{{/operations}} diff --git a/modules/swagger-codegen/src/main/resources/asyncscala/client.mustache b/modules/swagger-codegen/src/main/resources/asyncscala/client.mustache new file mode 100644 index 00000000000..d652ab07a94 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/asyncscala/client.mustache @@ -0,0 +1,26 @@ +package {{package}} + +{{#imports}}import {{import}} +{{/imports}} +import com.wordnik.swagger.client._ +import apis._ +import java.io.Closeable + +class {{clientName}}(config: SwaggerConfig) extends Closeable { + val locator = config.locator + val name = config.name + + private[this] val client = transportClient + + protected def transportClient: TransportClient = new RestClient(config) + + {{#apiInfo}} + {{#apis}} + val {{name}} = new {{className}}(client, config) + {{/apis}} + {{/apiInfo}} + + def close() { + client.close() + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/asyncscala/model.mustache b/modules/swagger-codegen/src/main/resources/asyncscala/model.mustache new file mode 100644 index 00000000000..3892f28302e --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/asyncscala/model.mustache @@ -0,0 +1,15 @@ +package {{package}} + +import org.joda.time.DateTime + +{{#models}} + +{{#model}} +case class {{classname}} ( + {{#vars}} + + {{name}}: {{#isNotRequired}}Option[{{/isNotRequired}}{{datatype}}{{#isNotRequired}}]{{/isNotRequired}} {{#hasMore}},{{/hasMore}}{{#description}} // {{description}}{{/description}}{{newline}} + {{/vars}} +) +{{/model}} +{{/models}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/asyncscala/sbt.mustache b/modules/swagger-codegen/src/main/resources/asyncscala/sbt.mustache new file mode 100644 index 00000000000..86d4779456a --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/asyncscala/sbt.mustache @@ -0,0 +1,11 @@ +organization := "{{package}}" + +name := "{{projectName}}-client" + +libraryDependencies += "com.wordnik.swagger" %% "swagger-async-httpclient" % "0.3.0-WN5" + +libraryDependencies += "joda-time" % "joda-time" % "2.3" + +libraryDependencies += "org.joda" % "joda-convert" % "1.3.1" + +libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.0.13" % "provided" diff --git a/modules/swagger-codegen/src/main/resources/csharp/Newtonsoft.Json.dll b/modules/swagger-codegen/src/main/resources/csharp/Newtonsoft.Json.dll new file mode 100644 index 00000000000..26fdaffec14 Binary files /dev/null and b/modules/swagger-codegen/src/main/resources/csharp/Newtonsoft.Json.dll differ diff --git a/modules/swagger-codegen/src/main/resources/csharp/api.mustache b/modules/swagger-codegen/src/main/resources/csharp/api.mustache new file mode 100644 index 00000000000..3d556fa72f8 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/csharp/api.mustache @@ -0,0 +1,101 @@ + using System; + using System.Collections.Generic; + using {{invokerPackage}}; + using {{modelPackage}}; + {{#imports}} + {{/imports}} + + namespace {{package}} { + {{#operations}} + public class {{classname}} { + string basePath; + private readonly ApiInvoker apiInvoker = ApiInvoker.GetInstance(); + + public {{classname}}(String basePath = "{{basePath}}") + { + this.basePath = basePath; + } + + public ApiInvoker getInvoker() { + return apiInvoker; + } + + // Sets the endpoint base url for the services being accessed + public void setBasePath(string basePath) { + this.basePath = basePath; + } + + // Gets the endpoint base url for the services being accessed + public String getBasePath() { + return basePath; + } + + {{#operation}} + + /// + /// {{summary}} {{notes}} + /// + {{#allParams}}/// {{description}} + {{#hasMore}} {{/hasMore}}{{/allParams}} + /// + public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}} {{nickname}} ({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) { + // create path and map variables + var path = "{{path}}".Replace("{format}","json"){{#pathParams}}.Replace("{" + "{{paramName}}" + "}", apiInvoker.escapeString({{{paramName}}}.ToString())){{/pathParams}}; + + // query params + var queryParams = new Dictionary(); + var headerParams = new Dictionary(); + var formParams = new Dictionary(); + + {{#requiredParamCount}} + // verify required params are set + if ({{/requiredParamCount}}{{#requiredParams}} {{paramName}} == null {{#hasMore}}|| {{/hasMore}}{{/requiredParams}}{{#requiredParamCount}}) { + throw new ApiException(400, "missing required params"); + } + {{/requiredParamCount}} + + {{#queryParams}}if ({{paramName}} != null){ + string paramStr = ({{paramName}} is DateTime) ? ((DateTime)(object){{paramName}}).ToString("u") : Convert.ToString({{paramName}}); + queryParams.Add("{{paramName}}", paramStr); + } + {{/queryParams}} + + {{#headerParams}}headerParams.Add("{{paramName}}", {{paramName}}); + {{/headerParams}} + + {{#formParams}}if ({{paramName}} != null){ + if({{paramName}} is byte[]) { + formParams.Add("{{paramName}}", {{paramName}}); + } else { + string paramStr = ({{paramName}} is DateTime) ? ((DateTime)(object){{paramName}}).ToString("u") : Convert.ToString({{paramName}}); + formParams.Add("{{paramName}}", paramStr); + } + } + {{/formParams}} + + try { + if (typeof({{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}) == typeof(byte[])) { + var response = apiInvoker.invokeBinaryAPI(basePath, path, "GET", queryParams, null, headerParams, formParams); + return {{#returnType}}((object)response) as {{{returnType}}}{{/returnType}}; + } else { + var response = apiInvoker.invokeAPI(basePath, path, "{{httpMethod}}", queryParams, {{#bodyParam}}{{bodyParam}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}, headerParams, formParams); + if(response != null){ + return {{#returnType}}({{{returnType}}}) ApiInvoker.deserialize(response, typeof({{{returnType}}})){{/returnType}}; + } + else { + return {{#returnType}}null{{/returnType}}; + } + } + } catch (ApiException ex) { + if(ex.ErrorCode == 404) { + return {{#returnType}}null{{/returnType}}; + } + else { + throw ex; + } + } + } + {{/operation}} + } + {{/operations}} + } \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/csharp/apiException.mustache b/modules/swagger-codegen/src/main/resources/csharp/apiException.mustache new file mode 100644 index 00000000000..3b371aea9a8 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/csharp/apiException.mustache @@ -0,0 +1,21 @@ +using System; + +namespace {{invokerPackage}} { + public class ApiException : Exception { + + private int errorCode = 0; + + public ApiException() {} + + public int ErrorCode { + get + { + return errorCode; + } + } + + public ApiException(int errorCode, string message) : base(message) { + this.errorCode = errorCode; + } + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/csharp/apiInvoker.mustache b/modules/swagger-codegen/src/main/resources/csharp/apiInvoker.mustache new file mode 100644 index 00000000000..f7c76ee2c56 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/csharp/apiInvoker.mustache @@ -0,0 +1,207 @@ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Net; + using System.Text; + using Newtonsoft.Json; + + namespace {{invokerPackage}} { + public class ApiInvoker { + private static readonly ApiInvoker _instance = new ApiInvoker(); + private Dictionary defaultHeaderMap = new Dictionary(); + + public static ApiInvoker GetInstance() { + return _instance; + } + + public void addDefaultHeader(string key, string value) { + defaultHeaderMap.Add(key, value); + } + + public string escapeString(string str) { + return str; + } + + public static object deserialize(string json, Type type) { + try + { + return JsonConvert.DeserializeObject(json, type); + } + catch (IOException e) { + throw new ApiException(500, e.Message); + } + + } + + public static string serialize(object obj) { + try + { + return obj != null ? JsonConvert.SerializeObject(obj) : null; + } + catch (Exception e) { + throw new ApiException(500, e.Message); + } + } + + public string invokeAPI(string host, string path, string method, Dictionary queryParams, object body, Dictionary headerParams, Dictionary formParams) + { + return invokeAPIInternal(host, path, method, false, queryParams, body, headerParams, formParams) as string; + } + + public byte[] invokeBinaryAPI(string host, string path, string method, Dictionary queryParams, object body, Dictionary headerParams, Dictionary formParams) + { + return invokeAPIInternal(host, path, method, true, queryParams, body, headerParams, formParams) as byte[]; + } + + private object invokeAPIInternal(string host, string path, string method, bool binaryResponse, Dictionary queryParams, object body, Dictionary headerParams, Dictionary formParams) { + var b = new StringBuilder(); + + foreach (var queryParamItem in queryParams) + { + var value = queryParamItem.Value; + if (value == null) continue; + b.Append(b.ToString().Length == 0 ? "?" : "&"); + b.Append(escapeString(queryParamItem.Key)).Append("=").Append(escapeString(value)); + } + + var querystring = b.ToString(); + + host = host.EndsWith("/") ? host.Substring(0, host.Length - 1) : host; + + var client = WebRequest.Create(host + path + querystring); + client.Method = method; + + byte[] formData = null; + if (formParams.Count > 0) + { + string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid()); + client.ContentType = "multipart/form-data; boundary=" + formDataBoundary; + formData = GetMultipartFormData(formParams, formDataBoundary); + client.ContentLength = formData.Length; + } + else + { + client.ContentType = "application/json"; + } + + foreach (var headerParamsItem in headerParams) + { + client.Headers.Add(headerParamsItem.Key, headerParamsItem.Value); + } + foreach (var defaultHeaderMapItem in defaultHeaderMap.Where(defaultHeaderMapItem => !headerParams.ContainsKey(defaultHeaderMapItem.Key))) + { + client.Headers.Add(defaultHeaderMapItem.Key, defaultHeaderMapItem.Value); + } + + switch (method) + { + case "GET": + break; + case "POST": + case "PUT": + case "DELETE": + using (Stream requestStream = client.GetRequestStream()) + { + if (formData != null) + { + requestStream.Write(formData, 0, formData.Length); + } + + var swRequestWriter = new StreamWriter(requestStream); + swRequestWriter.Write(serialize(body)); + swRequestWriter.Close(); + } + break; + default: + throw new ApiException(500, "unknown method type " + method); + } + + try + { + var webResponse = (HttpWebResponse)client.GetResponse(); + if (webResponse.StatusCode != HttpStatusCode.OK) + { + webResponse.Close(); + throw new ApiException((int)webResponse.StatusCode, webResponse.StatusDescription); + } + + if (binaryResponse) + { + using (var memoryStream = new MemoryStream()) + { + webResponse.GetResponseStream().CopyTo(memoryStream); + return memoryStream.ToArray(); + } + } + else + { + using (var responseReader = new StreamReader(webResponse.GetResponseStream())) + { + var responseData = responseReader.ReadToEnd(); + return responseData; + } + } + } + catch(WebException ex) + { + var response = ex.Response as HttpWebResponse; + int statusCode = 0; + if (response != null) + { + statusCode = (int)response.StatusCode; + response.Close(); + } + throw new ApiException(statusCode, ex.Message); + } + } + + private static byte[] GetMultipartFormData(Dictionary postParameters, string boundary) + { + Stream formDataStream = new System.IO.MemoryStream(); + bool needsCLRF = false; + + foreach (var param in postParameters) + { + // Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added. + // Skip it on the first parameter, add it to subsequent parameters. + if (needsCLRF) + formDataStream.Write(Encoding.UTF8.GetBytes("\r\n"), 0, Encoding.UTF8.GetByteCount("\r\n")); + + needsCLRF = true; + + if (param.Value is byte[]) + { + string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n", + boundary, + param.Key, + "application/octet-stream"); + formDataStream.Write(Encoding.UTF8.GetBytes(postData), 0, Encoding.UTF8.GetByteCount(postData)); + + // Write the file data directly to the Stream, rather than serializing it to a string. + formDataStream.Write((param.Value as byte[]), 0, (param.Value as byte[]).Length); + } + else + { + string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}", + boundary, + param.Key, + param.Value); + formDataStream.Write(Encoding.UTF8.GetBytes(postData), 0, Encoding.UTF8.GetByteCount(postData)); + } + } + + // Add the end of the request. Start with a newline + string footer = "\r\n--" + boundary + "--\r\n"; + formDataStream.Write(Encoding.UTF8.GetBytes(footer), 0, Encoding.UTF8.GetByteCount(footer)); + + // Dump the Stream into a byte[] + formDataStream.Position = 0; + byte[] formData = new byte[formDataStream.Length]; + formDataStream.Read(formData, 0, formData.Length); + formDataStream.Close(); + + return formData; + } + } + } diff --git a/modules/swagger-codegen/src/main/resources/csharp/compile.mustache b/modules/swagger-codegen/src/main/resources/csharp/compile.mustache new file mode 100644 index 00000000000..be16fb1636e --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/csharp/compile.mustache @@ -0,0 +1,2 @@ +SET CSCPATH=%SYSTEMROOT%\Microsoft.NET\Framework\v4.0.30319 +%CSCPATH%\csc /reference:bin/Newtonsoft.Json.dll /target:library /out:bin/{{invokerPackage}}.dll /recurse:src\*.cs /doc:bin/{{invokerPackage}}.xml \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/csharp/model.mustache b/modules/swagger-codegen/src/main/resources/csharp/model.mustache new file mode 100644 index 00000000000..d9ef4ffbedd --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/csharp/model.mustache @@ -0,0 +1,30 @@ +using System; +using System.Text; +using System.Collections; +using System.Collections.Generic; + +{{#models}} +{{#model}} +namespace {{package}} { + public class {{classname}} { + {{#vars}} + + {{#description}}/* {{{description}}} */ + {{/description}} + public {{{datatype}}} {{name}} { get; set; } + + {{/vars}} + + public override string ToString() { + var sb = new StringBuilder(); + sb.Append("class {{classname}} {\n"); + {{#vars}} + sb.Append(" {{name}}: ").Append({{name}}).Append("\n"); + {{/vars}} + sb.Append("}\n"); + return sb.ToString(); + } + } + {{/model}} + {{/models}} +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/flash/ASAXB-0.1.1.swc b/modules/swagger-codegen/src/main/resources/flash/ASAXB-0.1.1.swc new file mode 100644 index 00000000000..c9359026784 Binary files /dev/null and b/modules/swagger-codegen/src/main/resources/flash/ASAXB-0.1.1.swc differ diff --git a/modules/swagger-codegen/src/main/resources/flash/AirExecutorApp-app.xml b/modules/swagger-codegen/src/main/resources/flash/AirExecutorApp-app.xml new file mode 100644 index 00000000000..1dbaf98e644 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/AirExecutorApp-app.xml @@ -0,0 +1,146 @@ + + + + + + + AirExecutorApp + + + AirExecutorApp + + + AirExecutorApp + + + v1 + + + + + + + + + + + + + + + AirExecutorApp.swf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/swagger-codegen/src/main/resources/flash/ApiClientEvent.as b/modules/swagger-codegen/src/main/resources/flash/ApiClientEvent.as new file mode 100644 index 00000000000..313da09ea78 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/ApiClientEvent.as @@ -0,0 +1,36 @@ +package com.wordnik.swagger.event { +import com.wordnik.swagger.event.Response; + +import flash.events.Event; + +/** + * Event dispatched by the SDK to communicate success events and failure events. + * If a custom dispatcher has been assigned by the consumer on the generated client then the dispatcher dispatches + * the ApiClientEvent to indicate success or failure of the invocation using the Response + */ +public class ApiClientEvent extends Event{ + + /** + * Event type to indicate a unsuccessful invocation + */ + public static const FAILURE_EVENT:String = "unsuccesfulInvocation"; + + /** + * Event type to indicate a successful invocation + */ + public static const SUCCESS_EVENT:String = "successfulInvocation"; + + /** + * The Response object which contains response info + */ + public var response: Response; + /** + * Any additional info + */ + public var message:String; + + public function ApiClientEvent(type:String,bubbles:Boolean = false,cancelable:Boolean = false) { + super(type, bubbles, cancelable); + } +} +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/flash/ApiError.as b/modules/swagger-codegen/src/main/resources/flash/ApiError.as new file mode 100644 index 00000000000..13d09415829 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/ApiError.as @@ -0,0 +1,10 @@ +package com.wordnik.swagger.exception +{ + public class ApiError extends Error + { + public function ApiError(id:*=0, message:*="") + { + super(message,id); + } + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/flash/ApiErrorCodes.as b/modules/swagger-codegen/src/main/resources/flash/ApiErrorCodes.as new file mode 100644 index 00000000000..abe12178361 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/ApiErrorCodes.as @@ -0,0 +1,34 @@ +package com.wordnik.swagger.exception +{ + public class ApiErrorCodes + { + /** + * System exception. + */ + public static const SYSTEM_EXCEPTION: Number = 0; + + /** + * With Arguments as current key. + */ + public static const API_KEY_NOT_VALID: Number = 1000; + /** + * With arguments as current token value + */ + public static const AUTH_TOKEN_NOT_VALID: Number = 1001; + /** + * With arguments as input JSON and output class anme + */ + public static const ERROR_CONVERTING_JSON_TO_JAVA: Number = 1002; + /** + * With arguments as JAVA class name + */ + public static const ERROR_CONVERTING_JAVA_TO_JSON: Number = 1003; + + public static const ERROR_FROM_WEBSERVICE_CALL: Number = 1004; + /** + * With arguments as current API server name + */ + public static const API_SERVER_NOT_VALID: Number = 1005; + + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/flash/ApiInvoker.as b/modules/swagger-codegen/src/main/resources/flash/ApiInvoker.as new file mode 100644 index 00000000000..40ad41af65f --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/ApiInvoker.as @@ -0,0 +1,289 @@ +package com.wordnik.swagger.common +{ +import asaxb.xml.bind.ASAXBContext; +import asaxb.xml.bind.Unmarshaller; + +import com.wordnik.swagger.event.ApiClientEvent; +import com.wordnik.swagger.event.Response; +import com.wordnik.swagger.common.ApiUserCredentials; + +import flash.events.EventDispatcher; +import flash.utils.Dictionary; +import flash.utils.describeType; +import flash.xml.XMLDocument; +import flash.xml.XMLNode; + +import mx.messaging.ChannelSet; +import mx.messaging.channels.HTTPChannel; +import mx.messaging.messages.HTTPRequestMessage; +import mx.rpc.AsyncToken; +import mx.rpc.events.FaultEvent; +import mx.rpc.events.ResultEvent; +import mx.rpc.http.HTTPService; +import mx.rpc.xml.SimpleXMLEncoder; +import mx.utils.ObjectUtil; + + +public class ApiInvoker extends EventDispatcher +{ + + private var _apiUsageCredentials:ApiUserCredentials; + internal var _apiProxyServerUrl:String = ""; + private var _baseUrl: String = ""; + internal var _useProxyServer: Boolean = true; + private var _proxyHostName:String = ""; + private var _apiPath: String = ""; + private var _proxyPath: String = ""; + + public var _apiEventNotifier:EventDispatcher; + + private static const DELETE_DATA_DUMMY:String = "dummyDataRequiredForDeleteOverride"; + private static const X_HTTP_OVERRIDE_KEY:String = "X-HTTP-Method-Override"; + private static const CONTENT_TYPE_HEADER_KEY:String = "Content-Type"; + + public function ApiInvoker(apiUsageCredentials: ApiUserCredentials, eventNotifier: EventDispatcher, useProxy: Boolean = true) { + _apiUsageCredentials = apiUsageCredentials; + _useProxyServer = useProxy; + if(_apiUsageCredentials.hostName != null){ + _proxyHostName = _apiUsageCredentials.hostName; + } + _apiPath = _apiUsageCredentials.apiPath; + _proxyPath = _apiUsageCredentials.proxyPath; + _apiProxyServerUrl = _apiUsageCredentials.apiProxyServerUrl; + _apiEventNotifier = eventNotifier; + } + + public function invokeAPI(resourceURL: String, method: String, queryParams: Dictionary, postObject: Object, headerParams: Dictionary): AsyncToken { + //make the communication + if(_useProxyServer) { + resourceURL = _apiProxyServerUrl + resourceURL; + } + else{ + resourceURL = "http://"+ _proxyHostName + _apiPath + resourceURL; + } + + var counter: int = 0; + var symbol: String = "&"; + var paramValue: Object; + for (var paramName:String in queryParams) { + paramValue = queryParams[paramName]; + //var key:String = paramName; + // do stuff + symbol = "&"; + if(counter == 0){ + symbol = "?"; + } + resourceURL = resourceURL + symbol + paramName + "=" + paramValue.toString(); + counter++; + + } +// trace(resourceURL); + //create a httpservice and invoke the rest url waiting for response + var requestHeader:Object = new Object(); + if(headerParams != null) { + for(var key: String in headerParams) { + requestHeader[key] = headerParams[key]; + } + } + + resourceURL = ApiUrlHelper.appendTokenInfo(resourceURL, requestHeader, _apiUsageCredentials); + + var bodyData:String = marshal(postObject).toString();//restRequest.postData; + + return doRestCall(resourceURL, onApiRequestResult, onApiRequestFault, method, bodyData, requestHeader, "application/xml"); + + + } + + private function doRestCall( url : String, resultFunction : Function, faultFunction : Function = null, + restMethod : String = "GET", + bodyData : Object = null, headers: Object = null, contentType:String = "application/xml" ) : AsyncToken + { + var httpService : HTTPService = new HTTPService( ); + + if(headers == null){ + headers = new Object(); + } + httpService.method = restMethod; + + if ( restMethod.toUpperCase() != HTTPRequestMessage.GET_METHOD ) + { + //httpService.method = HTTPRequestMessage.POST_METHOD; - not required as we're using the proxy + if( bodyData == null ) + { + bodyData = new Object(); + } + + if(restMethod == HTTPRequestMessage.DELETE_METHOD){ + headers[X_HTTP_OVERRIDE_KEY]= HTTPRequestMessage.DELETE_METHOD; + bodyData = DELETE_DATA_DUMMY; + } + else if(restMethod == HTTPRequestMessage.PUT_METHOD){ + headers[X_HTTP_OVERRIDE_KEY]= HTTPRequestMessage.PUT_METHOD; + } + else{ + headers[CONTENT_TYPE_HEADER_KEY]= contentType; + } + } + else + { + //if the request type is GET and content type is xml then the Flex HTTPService converts it to a POST ... yeah + contentType = null; + } + + httpService.url = url; + httpService.contentType = contentType; + httpService.resultFormat = "e4x"; + httpService.headers = headers; + httpService.addEventListener( ResultEvent.RESULT, resultFunction ); + if( faultFunction != null ) + { + httpService.addEventListener( FaultEvent.FAULT, faultFunction ); + } + if(_useProxyServer){ + httpService.useProxy = true; + + var channelSet: ChannelSet = new ChannelSet(); + var httpChannel: HTTPChannel = new HTTPChannel(); + httpChannel.uri = ApiUrlHelper.getProxyUrl(_proxyHostName, _proxyPath); + channelSet.addChannel(httpChannel); + httpService.channelSet = channelSet; + } + + return httpService.send( bodyData ); + } + + private function onApiRequestResult(event:ResultEvent):void + { + var completionListener: Function = event.token.completionListener; + var result: Object = event.result; + var resultType: Class = event.token.returnType; + var resultObject:Object; + if(resultType != null) { + var context:ASAXBContext = ASAXBContext.newInstance(resultType); + var unmarshaller:Unmarshaller = context.createUnmarshaller(); + var resultXML: XML = new XML(event.result); + try{ + resultObject = unmarshaller.unmarshal(resultXML); + } + catch(error: TypeError){ + var errorResponse: Response = new Response(false, null, "Could not unmarshall response"); + if (_apiEventNotifier != null) { //dispatch event via assigned dispatcher + var failureEvent: ApiClientEvent = new ApiClientEvent(event.token.completionEventType); + failureEvent.response = errorResponse; + _apiEventNotifier.dispatchEvent(failureEvent); + } + } + + if(resultObject is ListWrapper){ + resultObject = ListWrapper(resultObject).getList(); + } + } + + var response : Response = new Response(true, resultObject); + response.requestId = event.token.requestId; + var successEventType: String = event.token.completionEventType != null ? event.token.completionEventType : ApiClientEvent.SUCCESS_EVENT; + + if (_apiEventNotifier != null) { //dispatch event via assigned dispatcher + var successEvent: ApiClientEvent = new ApiClientEvent(successEventType); + successEvent.response = response; + _apiEventNotifier.dispatchEvent(successEvent); + } + } + + private function onApiRequestFault(event:FaultEvent):void + { + var completionListener: Function = event.token.completionListener; + if(completionListener != null){ + completionListener.call( null, new Response( false, null, event.fault.faultString) ); + } + + var failureEventType: String = event.token.completionEventType != null ? event.token.completionEventType : ApiClientEvent.FAILURE_EVENT; + + if (_apiEventNotifier != null) { //dispatch event via assigned dispatcher + var failureEvent: ApiClientEvent = new ApiClientEvent(failureEventType); + failureEvent.response = new Response( false, null, event.fault.faultString); + _apiEventNotifier.dispatchEvent(failureEvent); + } + } + + + public function marshal(source:Object):Object { +// trace("marshal got - " + source) + if(source is String) { + return source; + } else if(source is Array && source.length > 0) { + var writer:XMLWriter=new XMLWriter(); + var sourceArray: Array = source as Array; + var arrayEnclosure: String = getArrayEnclosure(sourceArray); + writer.xml.setName(arrayEnclosure); + + for (var i:int = 0; i < sourceArray.length; i++) { + var o: Object = sourceArray[i]; + writer.xml.appendChild(marshal(o)); + } + return writer.xml; + } else + return marshalObject(source); + } + + public function marshalObject(source:Object):XML + { + var writer:XMLWriter=new XMLWriter(); + var objDescriptor:XML=describeType(source); + var property:XML; + var propertyType:String; + var propertyValue:Object; + + var qualifiedClassName:String=objDescriptor.@name; + qualifiedClassName=qualifiedClassName.replace("::","."); + var className: String = qualifiedClassName.substring(qualifiedClassName.lastIndexOf(".") + 1); + className = className().toLowerCase() + className.substring(1); + writer.xml.setName(className); + + for each(property in objDescriptor.elements("variable")){ + propertyValue=source[property.@name]; + if (propertyValue!=null){ + if (ObjectUtil.isSimple(propertyValue)){ + writer.addProperty(property.@name, propertyValue.toString()); + } + else { + writer.addProperty(property.@name, marshal(propertyValue).toXMLString()); + } + } + } + for each(property in objDescriptor.elements("accessor")){ + if (property.@access=="readonly"){ + continue; + } + propertyValue=source[property.@name]; + if (source[property.@name]!=null){ + if (ObjectUtil.isSimple(propertyValue)){ + writer.addProperty(property.@name, propertyValue.toString()); + } + else { + writer.addProperty(property.@name, marshal(propertyValue).toXMLString()); + } + } + } + return writer.xml; + } + + public function escapeString(str: String): String { + return str; + } + + private function getArrayEnclosure(arr: Array) : String { + if(arr != null && arr.length > 0) { + var className: String = flash.utils.getQualifiedClassName(arr[0]) + if(className.indexOf("::") > 0) + className = className.substr(className.indexOf("::") + 2, className.length) + + return className.substring(0, 1).toLowerCase() + className.substring(1, className.length) + "s"; + } else + return ""; + } + + +} +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/flash/ApiUrlHelper.as b/modules/swagger-codegen/src/main/resources/flash/ApiUrlHelper.as new file mode 100644 index 00000000000..affa1eb0ff9 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/ApiUrlHelper.as @@ -0,0 +1,41 @@ +package com.wordnik.swagger.common { +import com.wordnik.swagger.common.ApiUserCredentials; + +/** + * @private + * Internal class for the Rest client + */ +internal class ApiUrlHelper { + + private static const API_URL_KEY:String = "api_key"; + private static const AUTH_TOKEN_URL_KEY:String = "auth_token"; + + private static const HTTP_URL_PREFIX:String = "http://"; + + internal static function appendTokenInfo(restUrl:String, requestHeader: Object, credentials: ApiUserCredentials): String { + //checks for the presence api credentials on client initialization and not repeated here + if(restUrl.indexOf("?") == -1){ + restUrl += ( "?" + API_URL_KEY + "=" + credentials.apiToken ); + } + else{ + restUrl += ( "&" + API_URL_KEY + "=" + credentials.apiToken ); + } + requestHeader.api_key = credentials.apiToken; + + if(credentials.authToken != null && credentials.authToken != ""){ + restUrl += ( "&" + AUTH_TOKEN_URL_KEY + "=" + credentials.authToken ); + requestHeader.auth_token = credentials.authToken; + } + + return restUrl; + } + + internal static function getProxyUrl(hostName: String, proxyPath: String): String{ + if (hostName(hostName.length - 1) == "/") //remove trailing slash + { + hostName = hostName.substring(0, hostName.length - 1); + } + return HTTP_URL_PREFIX + hostName + proxyPath; + } +} +} diff --git a/modules/swagger-codegen/src/main/resources/flash/ApiUserCredentials.as b/modules/swagger-codegen/src/main/resources/flash/ApiUserCredentials.as new file mode 100644 index 00000000000..a7536c213e2 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/ApiUserCredentials.as @@ -0,0 +1,63 @@ +package com.wordnik.swagger.common { + +/** + * Api account credentials. + * + */ +public class ApiUserCredentials { + /** + * An apitoken that is passed along with the requests + */ + public var apiToken:String; + /** + * A valid auth_token which could be necessary for certain operations + */ + public var authToken:String; + /** + * The userId which could be required for certain operations + */ + public var userId:Number; + /** + * The host name for the Rest API eg. api.companyName.com + */ + public var hostName:String; + + /** + * The base path to the api resources - used along with the hostname + * eg. /v4 + */ + public var apiPath: String; + + /** + * The base path to the blazeds proxy + * eg. /v4/messagebroker/restproxy + */ + public var proxyPath: String; + + /** + * If a proxy server has been set up for the services specify the URL here. This value is used when the Api is invoked with + * the value useProxy as true + */ + public var apiProxyServerUrl: String; + + /** + * Constructor of ApiUserCredentials + * @param apiToken An apitoken that is passed along with the requests + * @param authToken A valid auth_token which could necessary for certain operations + * @param hostName The host name for the Rest API eg. api.companyName.com + * @param userId The userId which is required for certain operations - currently, get user lists + */ + public function ApiUserCredentials(hostName: String, apiPath: String, apiToken: String, + authToken: String = null, userId: Number = -1, apiProxyServerUrl: String="", + proxyPath: String = null) { + this.hostName = hostName; + this.apiToken = apiToken; + this.authToken = authToken; + this.userId = userId; + this.apiPath = apiPath; + this.apiProxyServerUrl = apiProxyServerUrl; + this.proxyPath = proxyPath; + } + +} +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/flash/ListWrapper.as b/modules/swagger-codegen/src/main/resources/flash/ListWrapper.as new file mode 100644 index 00000000000..1ea2ebead00 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/ListWrapper.as @@ -0,0 +1,9 @@ +package com.wordnik.swagger.common +{ + public interface ListWrapper + { + + function getList(): Array; + + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/flash/Response.as b/modules/swagger-codegen/src/main/resources/flash/Response.as new file mode 100644 index 00000000000..56cceb61959 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/Response.as @@ -0,0 +1,56 @@ +package com.wordnik.swagger.event { + +/** + * Response contains info on the result of an API invocation. + * A completion listener will expect this Response object. + */ +public class Response { + + /** + * Indicates whether the invoked operation failed or succeeded + */ + public var isSuccess:Boolean; + + /** + * The payload of the succesful operation eg. a Word in a WordRequest + */ + public var payload:Object; + + /** + * Error message in case of failure + */ + public var errorMessage:String; + + /** + * A request Id that was passed in by the user as a param when invoking the operation + */ + public var requestId:String; + private static const API_ERROR_MSG:String = "Api error response: "; + + public function Response(isSuccessful: Boolean, payload: Object = null, errorMessage: String = null, requestId: String = null) { + this.isSuccess = isSuccessful; + this.payload = payload; + this.errorMessage = getFriendlyMessage(errorMessage); + } + + private static function getFriendlyMessage(errorMessage: String): String{ + var result: String = errorMessage; + if(errorMessage == null) + return null; + var errorCode: String; + var errorCodeArray: Array = errorMessage.match(/(?<=HTTP\/1.1 )[0-9][0-9][0-9]/); + if(errorCodeArray != null && errorCodeArray.length == 1){ + errorCode = String(errorCodeArray[0]); + } + var msgArray: Array = errorMessage.match(/(?<=HTTP\/1.1 [0-9][0-9][0-9] )[^]*/); + if(msgArray != null && msgArray.length == 1){ + result = API_ERROR_MSG + String(msgArray[0]); + } + return result; + } + + public function toString(): String { + return "Response (requestId:" + requestId + "; isSuccess:" + isSuccess + "; errorMessage:" + errorMessage + "; payload:" + payload + ")"; + } +} +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/flash/SwaggerApi.as b/modules/swagger-codegen/src/main/resources/flash/SwaggerApi.as new file mode 100644 index 00000000000..a78f3105cb1 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/SwaggerApi.as @@ -0,0 +1,75 @@ +package com.wordnik.swagger.common +{ + import com.wordnik.swagger.common.ApiUserCredentials; + + import flash.events.EventDispatcher; + import flash.events.IEventDispatcher; + + import mx.utils.UIDUtil; + + public class SwaggerApi extends EventDispatcher + { + + protected var _apiUsageCredentials:ApiUserCredentials; + protected var _apiEventNotifier:EventDispatcher; + protected var _apiInvoker: ApiInvoker; + + protected var _useProxyServer: Boolean = false; + + + /** + * Constructor for the api client + * @param apiCredentials Wrapper object for tokens and hostName required towards authentication + * @param eventDispatcher Optional event dispatcher that when provided is used by the SDK to dispatch any Response + */ + public function SwaggerApi(apiCredentials: ApiUserCredentials, eventDispatcher: EventDispatcher = null) { + super(); + _apiUsageCredentials = apiCredentials; + _apiEventNotifier = eventDispatcher; + } + + public function useProxyServer(value:Boolean, proxyServerUrl: String = null):void { + _useProxyServer = value; + } + + protected function getApiInvoker():ApiInvoker { + if(_apiInvoker == null){ + if(_apiEventNotifier == null){ + _apiEventNotifier = this; + } + _apiInvoker = new ApiInvoker(_apiUsageCredentials, _apiEventNotifier, _useProxyServer); + } + return _apiInvoker; + } + + protected function getUniqueId():String { + return UIDUtil.createUID(); + } + + /** + * Method for returning the path value + * For a string value an empty value is returned if the value is null + * @param value + * @return + */ + protected static function toPathValue(value: Object): String { + if(value is Array){ + return arrayToPathValue(value as Array); + } + return value == null ? "" : value.toString(); + } + + /** + * Method for returning a path value + * For a list of objects a comma separated string is returned + * @param objects + * @return + */ + protected static function arrayToPathValue(objects: Array): String { + var out: String = ""; + + return objects.join(","); + } + + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/flash/XMLWriter.as b/modules/swagger-codegen/src/main/resources/flash/XMLWriter.as new file mode 100644 index 00000000000..067f49e6301 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/XMLWriter.as @@ -0,0 +1,28 @@ +package com.wordnik.swagger.common +{ + public class XMLWriter + { + public var xml:XML; + + public function XMLWriter() + { + xml=; + } + + public function reset():void { + xml=new XML(); + } + + public function addProperty(propertyName:String, propertyValue:String):XML { + var xmlProperty:XML= + xmlProperty.setName(propertyName); + xmlProperty.appendChild(propertyValue); + xml.appendChild(xmlProperty); + return xmlProperty; + } + + public function addAttribute(propertyName:String, attribute:String, attributeValue:String):void { + xml.elements(propertyName)[0].@[attribute]=attributeValue; + } + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/flash/api.mustache b/modules/swagger-codegen/src/main/resources/flash/api.mustache new file mode 100644 index 00000000000..647ec763a24 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/api.mustache @@ -0,0 +1,73 @@ +package {{package}} { + +import com.wordnik.swagger.common.ApiInvoker; +import com.wordnik.swagger.exception.ApiErrorCodes; +import com.wordnik.swagger.exception.ApiError; +import com.wordnik.swagger.common.ApiUserCredentials; +import com.wordnik.swagger.event.Response; +import com.wordnik.swagger.common.SwaggerApi; +{{#imports}}import {{import}}; +{{/imports}} + +import mx.rpc.AsyncToken; +import mx.utils.UIDUtil; +import flash.utils.Dictionary; +import flash.events.EventDispatcher; + +{{#operations}} +public class {{classname}} extends SwaggerApi { + /** + * Constructor for the {{classname}} api client + * @param apiCredentials Wrapper object for tokens and hostName required towards authentication + * @param eventDispatcher Optional event dispatcher that when provided is used by the SDK to dispatch any Response + */ + public function {{classname}}(apiCredentials: ApiUserCredentials, eventDispatcher: EventDispatcher = null) { + super(apiCredentials, eventDispatcher); + } + +{{#operation}} + public static const event_{{nickname}}: String = "{{nickname}}"; +{{/operation}} + +{{#operation}} + + /* + * Returns {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}} + */ + public function {{nickname}} ({{#allParams}}{{paramName}}: {{{dataType}}}{{#defaultValue}} = {{{defaultValue}}}{{/defaultValue}}{{#hasMore}}, {{/hasMore}}{{/allParams}}): String { + // create path and map variables + var path: String = "{{path}}".replace(/{format}/g,"xml"){{#pathParams}}.replace("{" + "{{paramName}}" + "}", getApiInvoker().escapeString({{{paramName}}})){{/pathParams}}; + + // query params + var queryParams: Dictionary = new Dictionary(); + var headerParams: Dictionary = new Dictionary(); + + {{#requiredParamCount}} + // verify required params are set + if({{/requiredParamCount}}{{#requiredParams}} {{paramName}} == null {{#hasMore}}|| {{/hasMore}}{{/requiredParams}}{{#requiredParamCount}}) { + throw new ApiError(400, "missing required params"); + } + {{/requiredParamCount}} + + {{#queryParams}}if("null" != String({{paramName}})) + queryParams["{{paramName}}"] = toPathValue({{paramName}}); + {{/queryParams}} + + {{#headerParams}}headerParams["{{paramName}}"] = toPathValue({{paramName}}); + {{/headerParams}} + + var token:AsyncToken = getApiInvoker().invokeAPI(path, "{{httpMethod}}", queryParams, {{#bodyParam}}{{bodyParam}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}, headerParams); + + var requestId: String = getUniqueId(); + + token.requestId = requestId; + token.completionEventType = "{{nickname}}"; + + token.returnType = {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}null {{/returnType}}; + return requestId; + + } + {{/operation}} +} + {{/operations}} +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/flash/as3corelib.swc b/modules/swagger-codegen/src/main/resources/flash/as3corelib.swc new file mode 100644 index 00000000000..12dd6b3b0a6 Binary files /dev/null and b/modules/swagger-codegen/src/main/resources/flash/as3corelib.swc differ diff --git a/modules/swagger-codegen/src/main/resources/flash/build.properties b/modules/swagger-codegen/src/main/resources/flash/build.properties new file mode 100644 index 00000000000..8e77d88c961 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/build.properties @@ -0,0 +1,29 @@ +# Window and document title for the documentation +title=Sample app AS3 SDK API Documentation + +#Path to the source folder where the .as files are located +sourcepath = ./src/main/flex + +# Class-folders you want to search for classes to be included in the docs, seperated by spaces (for example ../com/ ../net/ ) +# to include every .as and .mxml file within your project, just state ../ +domainextensions = ./src/main/flex + +# The Location of deployment library on your Computer (PC/Mac) for compiled SWC file +liboutputfolder = bin +liboutputfile = as3-sample-sdk.swc +libpath = lib + +# The Location of the output folder for your generated documents +docsoutputfolder = asdoc + +# The location of the test sources +testsourcepath = ./src/test/flex + +# Home directory for flex sdk, change this to build for Mac or PC using # as comment +FLEX4_SDK_HOME = /usr/local/flex_sdk_4.1.0/ +#FLEX4_SDK_HOME = /Applications/Adobe Flash Builder 4/sdks/4.1.0/ + +# The location of your asdoc.exe, change this to build for Mac or PC using # as comment +#asdoc.exe = C:/Program Files/Adobe/Flash Builder 4/sdks/3.5.0/bin/asdoc.exe +#asdoc.exe = /Applications/Adobe Flash Builder 4/sdks/3.5.0/bin/asdoc + diff --git a/modules/swagger-codegen/src/main/resources/flash/build.xml b/modules/swagger-codegen/src/main/resources/flash/build.xml new file mode 100644 index 00000000000..6861dd464ec --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/build.xml @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + docs created + + + + + + + + + + + + + + + + + + + + + + + + SWC created + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/flash/facetValue.as b/modules/swagger-codegen/src/main/resources/flash/facetValue.as new file mode 100644 index 00000000000..c6bfa1f27d1 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/facetValue.as @@ -0,0 +1,8 @@ +package com.wordnik.client.model { + + public class FacetValue { + public var value: String = null; + public var count: Number = 0; + } + +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/flash/flexunit-4.1.0_RC2-28-flex_3.5.0.12683.swc b/modules/swagger-codegen/src/main/resources/flash/flexunit-4.1.0_RC2-28-flex_3.5.0.12683.swc new file mode 100644 index 00000000000..e41bc68abd9 Binary files /dev/null and b/modules/swagger-codegen/src/main/resources/flash/flexunit-4.1.0_RC2-28-flex_3.5.0.12683.swc differ diff --git a/modules/swagger-codegen/src/main/resources/flash/flexunit-aircilistener-4.1.0_RC2-28-3.5.0.12683.swc b/modules/swagger-codegen/src/main/resources/flash/flexunit-aircilistener-4.1.0_RC2-28-3.5.0.12683.swc new file mode 100644 index 00000000000..8bbdf8b86a0 Binary files /dev/null and b/modules/swagger-codegen/src/main/resources/flash/flexunit-aircilistener-4.1.0_RC2-28-3.5.0.12683.swc differ diff --git a/modules/swagger-codegen/src/main/resources/flash/flexunit-cilistener-4.1.0_RC2-28-3.5.0.12683.swc b/modules/swagger-codegen/src/main/resources/flash/flexunit-cilistener-4.1.0_RC2-28-3.5.0.12683.swc new file mode 100644 index 00000000000..b69064ac765 Binary files /dev/null and b/modules/swagger-codegen/src/main/resources/flash/flexunit-cilistener-4.1.0_RC2-28-3.5.0.12683.swc differ diff --git a/modules/swagger-codegen/src/main/resources/flash/flexunit-core-flex-4.0.0.2-sdk3.5.0.12683.swc b/modules/swagger-codegen/src/main/resources/flash/flexunit-core-flex-4.0.0.2-sdk3.5.0.12683.swc new file mode 100644 index 00000000000..a90af750bb5 Binary files /dev/null and b/modules/swagger-codegen/src/main/resources/flash/flexunit-core-flex-4.0.0.2-sdk3.5.0.12683.swc differ diff --git a/modules/swagger-codegen/src/main/resources/flash/model.mustache b/modules/swagger-codegen/src/main/resources/flash/model.mustache new file mode 100644 index 00000000000..c3369514e80 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/model.mustache @@ -0,0 +1,40 @@ +package {{package}} { + +{{#imports}}import {{import}}; +{{/imports}} + +{{#models}} +{{#model}} + [XmlRootNode(name="{{classname}}")] + public class {{classname}} { + {{#vars}} + + {{#description}}/* {{description}} */ + {{/description}} + + {{#isList}} + // This declaration below of _{{name}}_obj_class is to force flash compiler to include this class + private var _{{name}}_obj_class: {{baseType}} = null; + [XmlElementWrapper(name="{{name}}")] + [XmlElements(name="{{nameSingular}}", type="{{baseType}}")] + {{/isList}} + {{#isNotContainer}}[XmlElement(name="{{name}}")] + {{/isNotContainer}} + public var {{name}}: {{{datatype}}} = {{{defaultValue}}}; + + {{/vars}} + + public function toString(): String { + var str: String = "{{classname}}: "; + {{#vars}} + str += " ({{name}}: " + {{name}} + ")"; + {{/vars}} + return str; + } + + +} +{{/model}} + {{/models}} + +} diff --git a/modules/swagger-codegen/src/main/resources/flash/modelList.mustache b/modules/swagger-codegen/src/main/resources/flash/modelList.mustache new file mode 100644 index 00000000000..b0c3bd73f83 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/flash/modelList.mustache @@ -0,0 +1,23 @@ +package {{package}} { + +import com.wordnik.swagger.common.ListWrapper; +{{#imports}}import {{import}}; +{{/imports}} + +{{#models}} +{{#model}} + public class {{classname}}List implements ListWrapper { + // This declaration below of _{{name}}_obj_class is to force flash compiler to include this class + private var _{{classVarName}}_obj_class: {{package}}.{{classname}} = null; + [XmlElements(name="{{classVarName}}", type="{{package}}.{{classname}}")] + public var {{classVarName}}: Array = new Array(); + + public function getList(): Array{ + return {{classVarName}}; + } + +} +{{/model}} + {{/models}} + +} diff --git a/modules/swagger-codegen/src/main/resources/htmlDocs/bodyParam.mustache b/modules/swagger-codegen/src/main/resources/htmlDocs/bodyParam.mustache new file mode 100644 index 00000000000..2fd81183a5b --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/htmlDocs/bodyParam.mustache @@ -0,0 +1,3 @@ +{{#isBodyParam}}
{{paramName}} {{^required}}(optional){{/required}}{{#required}}(required){{/required}}
+ +
Body Parameter — {{description}} {{#defaultValue}}default: {{{defaultValue}}}{{/defaultValue}}
{{/isBodyParam}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/htmlDocs/formParam.mustache b/modules/swagger-codegen/src/main/resources/htmlDocs/formParam.mustache new file mode 100644 index 00000000000..97f342e60d7 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/htmlDocs/formParam.mustache @@ -0,0 +1,3 @@ +{{#isFormParam}}
{{paramName}} {{^required}}(optional){{/required}}{{#required}}(required){{/required}}
+ +
Form Parameter — {{description}} {{#defaultValue}}default: {{{defaultValue}}}{{/defaultValue}}
{{/isFormParam}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/htmlDocs/headerParam.mustache b/modules/swagger-codegen/src/main/resources/htmlDocs/headerParam.mustache new file mode 100644 index 00000000000..903713493be --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/htmlDocs/headerParam.mustache @@ -0,0 +1,3 @@ +{{#isHeaderParam}}
{{paramName}} {{^required}}(optional){{/required}}{{#required}}(required){{/required}}
+ +
Header Parameter — {{description}} {{#defaultValue}}default: {{{defaultValue}}}{{/defaultValue}}
{{/isHeaderParam}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/htmlDocs/index.mustache b/modules/swagger-codegen/src/main/resources/htmlDocs/index.mustache new file mode 100644 index 00000000000..ccd35c8723d --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/htmlDocs/index.mustache @@ -0,0 +1,60 @@ + + + + API Reference + + + +

{{{appName}}}

+
{{{appDescription}}} for {{partner}}
+ {{#infoUrl}}
More information: {{{infoUrl}}}
{{/infoUrl}} + {{#infoEmail}}
Contact Info: {{{infoEmail}}}
{{/infoEmail}} +
{{{licenseInfo}}}
+
{{{licenseUrl}}}
+

Access

+
Access to the API requires an api key to be provided by {{partner}} for all requests. The api key is passed as a header with the name `api_key` and the value provided by Reverb Technologies, Inc. Unless otherwise agreed upon, access to the Reverb API is intended solely for usage by {{partner}} and not third parties.
+

Methods

+ {{#apiInfo}} + {{#apis}} + {{#operations}}{{#operation}} +
+
{{httpMethod}}: {{path}}
+
{{nickname}} {{summary}}
+
{{notes}}
+ +

Parameters

+
+ {{#allParams}}{{>queryParam}}{{>pathParam}}{{>bodyParam}}{{>headerParam}}{{>formParam}} + {{/allParams}} +
+

Return type

+ + + + {{#examples}} +

Example data

+
Content-Type: {{{contentType}}}
+
{{{example}}}
+ {{/examples}} +
+
+ {{/operation}}{{/operations}} + {{/apis}}{{/apiInfo}} + +

Models

+ {{#models}} + {{#model}} +
+

{{classname}}

+
+ {{#vars}}
{{name}} {{#isNotRequired}}(optional){{/isNotRequired}}
{{datatype}} {{description}}
+ {{/vars}} +
+
+ {{/model}} + {{/models}} + + + \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/htmlDocs/pathParam.mustache b/modules/swagger-codegen/src/main/resources/htmlDocs/pathParam.mustache new file mode 100644 index 00000000000..b47805a4f04 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/htmlDocs/pathParam.mustache @@ -0,0 +1,3 @@ +{{#isPathParam}}
{{paramName}} {{^required}}(optional){{/required}}{{#required}}(required){{/required}}
+ +
Path Parameter — {{description}} {{#defaultValue}}default: {{{defaultValue}}}{{/defaultValue}}
{{/isPathParam}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/htmlDocs/queryParam.mustache b/modules/swagger-codegen/src/main/resources/htmlDocs/queryParam.mustache new file mode 100644 index 00000000000..52147fbd718 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/htmlDocs/queryParam.mustache @@ -0,0 +1,3 @@ +{{#isQueryParam}}
{{paramName}} {{^required}}(optional){{/required}}{{#required}}(required){{/required}}
+ +
Query Parameter — {{description}} {{#defaultValue}}default: {{{defaultValue}}}{{/defaultValue}}
{{/isQueryParam}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/htmlDocs/style.css.mustache b/modules/swagger-codegen/src/main/resources/htmlDocs/style.css.mustache new file mode 100644 index 00000000000..0421bcc8c3c --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/htmlDocs/style.css.mustache @@ -0,0 +1,136 @@ +body { + font-family: Trebuchet MS, sans-serif; + font-size: 15px; + color: #444; + margin-right: 24px; +} + +h1 { + font-size: 25px; +} +h2 { + font-size: 20px; +} +h3 { + font-size: 16px; + font-weight: bold; +} +hr { + height: 1px; + border: 0; + color: #ddd; + background-color: #ddd; + display: none; +} + +.app-desc { + clear: both; + margin-left: 20px; +} +.param-name { + width: 100%; +} +.license-info { + margin-left: 20px; +} + +.license-url { + margin-left: 20px; +} + +.model { + margin: 0 0 0px 20px; +} + +.method { + margin-left: 20px; +} + +.method-notes { + margin: 10px 0 20px 0; + font-size: 90%; + color: #555; +} + +pre { + padding: 10px; +} + +pre.get { + background-color: #0f6ab4; +} + +pre.post { + background-color: #10a54a; +} + +pre.put { + background-color: #c5862b; +} + +pre.delete { + background-color: #a41e22; +} + +.huge { + color: #fff; +} + +pre.example { + background-color: #f3f3f3; + padding: 10px; + border: 1px solid #ddd; +} + +code { + white-space: pre; +} + +.nickname { + font-weight: bold; +} + +.method-path { + font-size: 1.5em; + background-color: #0f6ab4; +} + +.parameter { + width: 500px; +} + +.param { + width: 500px; + padding: 10px 0 0 20px; + font-weight: bold; +} + +.param-desc { + width: 700px; + padding: 0 0 0 20px; + color: #777; +} + +.param-type { + font-style: italic; +} + +.field-label { + padding: 0; + margin: 0; + clear: both; +} + +.field-items { + padding: 0 0 15px 0; + margin-bottom: 15px; +} + +.return-type { + clear: both; + padding-bottom: 10px; +} + +.param-header { + font-weight: bold; +} diff --git a/modules/swagger-codegen/src/main/resources/logback.xml b/modules/swagger-codegen/src/main/resources/logback.xml new file mode 100644 index 00000000000..c7d0db9d3a2 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/logback.xml @@ -0,0 +1,12 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + diff --git a/modules/swagger-codegen/src/main/resources/nodejs/README.mustache b/modules/swagger-codegen/src/main/resources/nodejs/README.mustache new file mode 100644 index 00000000000..881e7dd92c5 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nodejs/README.mustache @@ -0,0 +1,10 @@ +# Swagger generated server + +## Overview +This server was generated by the [swagger-codegen](https://github.com/wordnik/swagger-codegen) project. By using the +[swagger-spec](https://github.com/wordnik/swagger-core/wiki) from a remote server, you can easily generate a server stub. This +is an example of building a node.js server. + +This example uses the [expressjs](http://expressjs.com/) framework. To see how to make this your own, look here: + +[README](https://github.com/wordnik/swagger-codegen/tree/master/samples/server-generator/node) \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nodejs/api.mustache b/modules/swagger-codegen/src/main/resources/nodejs/api.mustache new file mode 100644 index 00000000000..82f0145ce8e --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nodejs/api.mustache @@ -0,0 +1,62 @@ +var swagger = require("swagger-node-express"); +var url = require("url"); +var errors = swagger.errors; +var params = swagger.params; + +/* add model includes */ + +function writeResponse (response, data) { + response.header('Access-Control-Allow-Origin', "*"); + response.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT"); + response.header("Access-Control-Allow-Headers", "Content-Type"); + response.header("Content-Type", "application/json; charset=utf-8"); + response.send(JSON.stringify(data)); +} + +exports.models = models = require("../models.js"); + +{{#operations}} +{{#operation}} +exports.{{nickname}} = { + 'spec': { + "description" : "Operations about pets", + "path" : "{{path}}", + "notes" : "{{{notes}}}", + "summary" : "{{{summary}}}", + "method": "{{httpMethod}}", + "params" : [{{#queryParams}} + params.query("{{paramName}}", "{{description}}", "{{swaggerDataType}}", {{#required}}true{{/required}}{{^required}}false{{/required}}, {{#allowMultiple}}true{{/allowMultiple}}{{^allowMultiple}}false{{/allowMultiple}}, "{{{allowableValues}}}"{{#defaultValue}}, {{{defaultValue}}}{{/defaultValue}}){{#hasMore}},{{/hasMore}} + {{/queryParams}}].concat([{{#pathParams}} + params.path("{{paramName}}", "{{description}}"){{#hasMore}},{{/hasMore}} + {{/pathParams}}]).concat([{{#headerParams}} + params.header("{{paramName}}", "{{description}}"){{#hasMore}},{{/hasMore}} + {{/headerParams}}]).concat([{{#bodyParams}} + params.body("body", "{{swaggerDataType}}", "{{description}}", {{#required}}{{required}}{{/required}}{{^required}}false{{/required}}) + {{/bodyParams}}]), + {{#returnContainer}} + "type": "{{returnType}}", + "items": { + {{#returnTypeIsPrimitive}}"type": "{{returnContainer}}"{{/returnTypeIsPrimitive}} + {{^returnTypeIsPrimitive}}"$ref": "{{returnContainer}}"{{/returnTypeIsPrimitive}} + }, + // container + {{/returnContainer}} + {{^returnContainer}} + "type" : "{{returnType}}", + {{/returnContainer}} + "responseMessages" : [errors.invalid('id'), errors.notFound('{{returnType}}')], + "nickname" : "{{nickname}}" + }, + 'action': function (req,res) { + {{#requiredParamCount}} + {{#requiredParams}} + if (!req.params.{{baseName}}) { + throw errors.invalid('{{baseName}}'); + } + {{/requiredParams}} + {{/requiredParamCount}} + writeResponse(res, {message: "how about implementing {{nickname}} as a {{httpMethod}} method?"}); + } +}; +{{/operation}} +{{/operations}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nodejs/main.mustache b/modules/swagger-codegen/src/main/resources/nodejs/main.mustache new file mode 100644 index 00000000000..6c8be317be6 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nodejs/main.mustache @@ -0,0 +1,52 @@ +var express = require("express") + , url = require("url") + , cors = require("cors") + , swagger = require("swagger-node-express") + , db = false + +var app = express(); +app.use(express.bodyParser()); + +var corsOptions = { + credentials: true, + origin: function(origin,callback) { + if(origin===undefined) { + callback(null,false); + } else { + callback(null,true); + } + } +}; + +app.use(cors(corsOptions)); + +{{#basePath}} +var subpath = express(); + +app.use("{{{basePath}}}", subpath); + +swagger.setAppHandler(subpath); +{{/basePath}} +{{^basePath}} +swagger.setAppHandler(app); +{{/basePath}} + +swagger.configureSwaggerPaths("", "api-docs", "") + +var models = require("./app/models.js"); + +{{#apiInfo}} +{{#apis}} +var {{classname}} = require("./{{apiFolder}}/{{classname}}.js"); +{{/apis}} +{{/apiInfo}} + +swagger.addModels(models) + {{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}.add{{httpMethod}}({{classname}}.{{nickname}}){{/operation}}{{/operations}} + {{/apis}}{{/apiInfo}}; + +// configures the app +swagger.configure("http://localhost:8002{{basePath}}", "0.1"); + +// start the server +app.listen(8002); diff --git a/modules/swagger-codegen/src/main/resources/nodejs/models.mustache b/modules/swagger-codegen/src/main/resources/nodejs/models.mustache new file mode 100644 index 00000000000..133fe7c1515 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nodejs/models.mustache @@ -0,0 +1,3 @@ +exports.models = { + {{#models}}{{#model}}"{{classVarName}}": {{{modelJson}}}{{#hasMoreModels}},{{/hasMoreModels}}{{/model}}{{/models}} +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nodejs/package.mustache b/modules/swagger-codegen/src/main/resources/nodejs/package.mustache new file mode 100755 index 00000000000..322dc819966 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nodejs/package.mustache @@ -0,0 +1,16 @@ +{ + "name": "{{{artifactId}}}", + "description": "Wordnik node.js server generator", + "version": "{{{artifactVersion}}}", + "homepage": "{{{homepage}}}", + "main": "./{{codeDir}}/main.js", + "engines": { + "node": ">= 0.8.x" + }, + "dependencies": { + "swagger-node-express": ">= 2.0.x", + "connect": ">= 1.8.x", + "cors": "2.1.1", + "express": "3.x" + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/objc/Podfile.mustache b/modules/swagger-codegen/src/main/resources/objc/Podfile.mustache new file mode 100644 index 00000000000..ee3f0856b6f --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/objc/Podfile.mustache @@ -0,0 +1,3 @@ +platform :ios, '6.0' +xcodeproj '{{projectName}}/{{projectName}}.xcodeproj' +pod 'AFNetworking', '~> 1.0' diff --git a/modules/swagger-codegen/src/main/resources/objc/SWGApiClient.h b/modules/swagger-codegen/src/main/resources/objc/SWGApiClient.h new file mode 100644 index 00000000000..aab60cd0595 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/objc/SWGApiClient.h @@ -0,0 +1,64 @@ +#import +#import "AFHTTPClient.h" + +@interface SWGApiClient : AFHTTPClient + +@property(nonatomic, assign) NSURLRequestCachePolicy cachePolicy; +@property(nonatomic, assign) NSTimeInterval timeoutInterval; +@property(nonatomic, assign) BOOL logRequests; +@property(nonatomic, assign) BOOL logCacheHits; +@property(nonatomic, assign) BOOL logServerResponses; +@property(nonatomic, assign) BOOL logJSON; +@property(nonatomic, assign) BOOL logHTTP; +@property(nonatomic, readonly) NSOperationQueue* queue; + ++(SWGApiClient *)sharedClientFromPool:(NSString *)baseUrl; + ++(NSOperationQueue*) sharedQueue; + ++(void)setLoggingEnabled:(bool) state; + ++(void)clearCache; + ++(void)setCacheEnabled:(BOOL) enabled; + ++(unsigned long)requestQueueSize; + ++(void) setOfflineState:(BOOL) state; + ++(AFNetworkReachabilityStatus) getReachabilityStatus; + ++(NSNumber*) nextRequestId; + ++(NSNumber*) queueRequest; + ++(void) cancelRequest:(NSNumber*)requestId; + ++(NSString*) escape:(id)unescaped; + ++(void) setReachabilityChangeBlock:(void(^)(int))changeBlock; + ++(void) configureCacheReachibilityForHost:(NSString*)host; + +-(void)setHeaderValue:(NSString*) value + forKey:(NSString*) forKey; + +-(NSNumber*) dictionary:(NSString*) path + method:(NSString*) method + queryParams:(NSDictionary*) queryParams + body:(id) body + headerParams:(NSDictionary*) headerParams + requestContentType:(NSString*) requestContentType + responseContentType:(NSString*) responseContentType + completionBlock:(void (^)(NSDictionary*, NSError *))completionBlock; + +-(NSNumber*) stringWithCompletionBlock:(NSString*) path + method:(NSString*) method + queryParams:(NSDictionary*) queryParams + body:(id) body + headerParams:(NSDictionary*) headerParams + requestContentType:(NSString*) requestContentType + responseContentType:(NSString*) responseContentType + completionBlock:(void (^)(NSString*, NSError *))completionBlock; +@end + diff --git a/modules/swagger-codegen/src/main/resources/objc/SWGApiClient.m b/modules/swagger-codegen/src/main/resources/objc/SWGApiClient.m new file mode 100644 index 00000000000..0b8be93ab5d --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/objc/SWGApiClient.m @@ -0,0 +1,419 @@ +#import "SWGApiClient.h" +#import "SWGFile.h" + +#import "AFJSONRequestOperation.h" + +@implementation SWGApiClient + +static long requestId = 0; +static bool offlineState = false; +static NSMutableSet * queuedRequests = nil; +static bool cacheEnabled = false; +static AFNetworkReachabilityStatus reachabilityStatus = AFNetworkReachabilityStatusNotReachable; +static NSOperationQueue* sharedQueue; +static void (^reachabilityChangeBlock)(int); +static bool loggingEnabled = false; + ++(void)setLoggingEnabled:(bool) state { + loggingEnabled = state; +} + ++(void)clearCache { + [[NSURLCache sharedURLCache] removeAllCachedResponses]; +} + ++(void)setCacheEnabled:(BOOL)enabled { + cacheEnabled = enabled; +} + ++(void)configureCacheWithMemoryAndDiskCapacity:(unsigned long) memorySize + diskSize:(unsigned long) diskSize { + NSAssert(memorySize > 0, @"invalid in-memory cache size"); + NSAssert(diskSize >= 0, @"invalid disk cache size"); + + NSURLCache *cache = + [[NSURLCache alloc] + initWithMemoryCapacity:memorySize + diskCapacity:diskSize + diskPath:@"swagger_url_cache"]; + + [NSURLCache setSharedURLCache:cache]; +} + ++(NSOperationQueue*) sharedQueue { + return sharedQueue; +} + ++(SWGApiClient *)sharedClientFromPool:(NSString *)baseUrl { + static NSMutableDictionary *_pool = nil; + if (queuedRequests == nil) { + queuedRequests = [[NSMutableSet alloc]init]; + } + if(_pool == nil) { + // setup static vars + // create queue + sharedQueue = [[NSOperationQueue alloc] init]; + + // create pool + _pool = [[NSMutableDictionary alloc] init]; + + // initialize URL cache + [SWGApiClient configureCacheWithMemoryAndDiskCapacity:4*1024*1024 diskSize:32*1024*1024]; + + // configure reachability + [SWGApiClient configureCacheReachibilityForHost:baseUrl]; + } + + @synchronized(self) { + SWGApiClient * client = [_pool objectForKey:baseUrl]; + if (client == nil) { + client = [[SWGApiClient alloc] initWithBaseURL:[NSURL URLWithString:baseUrl]]; + [client registerHTTPOperationClass:[AFJSONRequestOperation class]]; + client.parameterEncoding = AFJSONParameterEncoding; + [_pool setValue:client forKey:baseUrl ]; + if(loggingEnabled) + NSLog(@"new client for path %@", baseUrl); + } + if(loggingEnabled) + NSLog(@"returning client for path %@", baseUrl); + return client; + } +} + +-(void)setHeaderValue:(NSString*) value + forKey:(NSString*) forKey { + [self setDefaultHeader:forKey value:value]; +} + ++(unsigned long)requestQueueSize { + return [queuedRequests count]; +} + ++(NSNumber*) nextRequestId { + long nextId = ++requestId; + if(loggingEnabled) + NSLog(@"got id %ld", nextId); + return [NSNumber numberWithLong:nextId]; +} + ++(NSNumber*) queueRequest { + NSNumber* requestId = [SWGApiClient nextRequestId]; + if(loggingEnabled) + NSLog(@"added %@ to request queue", requestId); + [queuedRequests addObject:requestId]; + return requestId; +} + ++(void) cancelRequest:(NSNumber*)requestId { + [queuedRequests removeObject:requestId]; +} + ++(NSString*) escape:(id)unescaped { + if([unescaped isKindOfClass:[NSString class]]){ + return (NSString *)CFBridgingRelease + (CFURLCreateStringByAddingPercentEscapes( + NULL, + (__bridge CFStringRef) unescaped, + NULL, + (CFStringRef)@"!*'();:@&=+$,/?%#[]", + kCFStringEncodingUTF8)); + } + else { + return [NSString stringWithFormat:@"%@", unescaped]; + } +} + +-(Boolean) executeRequestWithId:(NSNumber*) requestId { + NSSet* matchingItems = [queuedRequests objectsPassingTest:^BOOL(id obj, BOOL *stop) { + if([obj intValue] == [requestId intValue]) + return TRUE; + else return FALSE; + }]; + + if(matchingItems.count == 1) { + if(loggingEnabled) + NSLog(@"removing request id %@", requestId); + [queuedRequests removeObject:requestId]; + return true; + } + else + return false; +} + +-(id)initWithBaseURL:(NSURL *)url { + self = [super initWithBaseURL:url]; + if (!self) + return nil; + return self; +} + ++(AFNetworkReachabilityStatus) getReachabilityStatus { + return reachabilityStatus; +} + ++(void) setReachabilityChangeBlock:(void(^)(int))changeBlock { + reachabilityChangeBlock = changeBlock; +} + ++(void) setOfflineState:(BOOL) state { + offlineState = state; +} + ++(void) configureCacheReachibilityForHost:(NSString*)host { + [[SWGApiClient sharedClientFromPool:host ] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { + reachabilityStatus = status; + switch (status) { + case AFNetworkReachabilityStatusUnknown: + if(loggingEnabled) + NSLog(@"reachability changed to AFNetworkReachabilityStatusUnknown"); + [SWGApiClient setOfflineState:true]; + break; + + case AFNetworkReachabilityStatusNotReachable: + if(loggingEnabled) + NSLog(@"reachability changed to AFNetworkReachabilityStatusNotReachable"); + [SWGApiClient setOfflineState:true]; + break; + + case AFNetworkReachabilityStatusReachableViaWWAN: + if(loggingEnabled) + NSLog(@"reachability changed to AFNetworkReachabilityStatusReachableViaWWAN"); + [SWGApiClient setOfflineState:false]; + break; + + case AFNetworkReachabilityStatusReachableViaWiFi: + if(loggingEnabled) + NSLog(@"reachability changed to AFNetworkReachabilityStatusReachableViaWiFi"); + [SWGApiClient setOfflineState:false]; + break; + default: + break; + } + // call the reachability block, if configured + if(reachabilityChangeBlock != nil) { + reachabilityChangeBlock(status); + } + }]; +} + +-(NSString*) pathWithQueryParamsToString:(NSString*) path + queryParams:(NSDictionary*) queryParams { + NSString * separator = nil; + int counter = 0; + + NSMutableString * requestUrl = [NSMutableString stringWithFormat:@"%@", path]; + if(queryParams != nil){ + for(NSString * key in [queryParams keyEnumerator]){ + if(counter == 0) separator = @"?"; + else separator = @"&"; + NSString * value; + if([[queryParams valueForKey:key] isKindOfClass:[NSString class]]){ + value = [SWGApiClient escape:[queryParams valueForKey:key]]; + } + else { + value = [NSString stringWithFormat:@"%@", [queryParams valueForKey:key]]; + } + [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, + [SWGApiClient escape:key], value]]; + counter += 1; + } + } + return requestUrl; +} + +- (NSString*)descriptionForRequest:(NSURLRequest*)request { + return [[request URL] absoluteString]; +} + +- (void)logRequest:(NSURLRequest*)request { + NSLog(@"request: %@", [self descriptionForRequest:request]); +} + +- (void)logResponse:(id)data forRequest:(NSURLRequest*)request error:(NSError*)error { + NSLog(@"request: %@ response: %@ ", [self descriptionForRequest:request], data ); +} + + +-(NSNumber*) dictionary:(NSString*) path + method:(NSString*) method + queryParams:(NSDictionary*) queryParams + body:(id) body + headerParams:(NSDictionary*) headerParams + requestContentType:(NSString*) requestContentType + responseContentType:(NSString*) responseContentType + completionBlock:(void (^)(NSDictionary*, NSError *))completionBlock { + + NSMutableURLRequest * request = nil; + + if ([body isKindOfClass:[SWGFile class]]){ + SWGFile * file = (SWGFile*) body; + + request = [self multipartFormRequestWithMethod:@"POST" + path:path + parameters:nil + constructingBodyWithBlock: ^(id formData) { + [formData appendPartWithFileData:[file data] + name:@"image" + fileName:[file name] + mimeType:[file mimeType]]; + }]; + } + else { + request = [self requestWithMethod:method + path:[self pathWithQueryParamsToString:path queryParams:queryParams] + parameters:body]; + } + BOOL hasHeaderParams = false; + if(headerParams != nil && [headerParams count] > 0) + hasHeaderParams = true; + if(offlineState) { + NSLog(@"%@ cache forced", path); + [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad]; + } + else if(!hasHeaderParams && [method isEqualToString:@"GET"] && cacheEnabled) { + NSLog(@"%@ cache enabled", path); + [request setCachePolicy:NSURLRequestUseProtocolCachePolicy]; + } + else { + NSLog(@"%@ cache disabled", path); + [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]; + } + + if(body != nil) { + if([body isKindOfClass:[NSDictionary class]] || [body isKindOfClass:[NSArray class]]){ + [request setValue:requestContentType forHTTPHeaderField:@"Content-Type"]; + } + else if ([body isKindOfClass:[SWGFile class]]) {} + else { + NSAssert(false, @"unsupported post type!"); + } + } + if(headerParams != nil){ + for(NSString * key in [headerParams keyEnumerator]){ + [request setValue:[headerParams valueForKey:key] forHTTPHeaderField:key]; + } + } + [request setValue:[headerParams valueForKey:responseContentType] forHTTPHeaderField:@"Accept"]; + + // Always disable cookies! + [request setHTTPShouldHandleCookies:NO]; + + + if (self.logRequests) { + [self logRequest:request]; + } + + NSNumber* requestId = [SWGApiClient queueRequest]; + AFJSONRequestOperation *op = + [AFJSONRequestOperation + JSONRequestOperationWithRequest:request + success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) { + if([self executeRequestWithId:requestId]) { + if(self.logServerResponses) + [self logResponse:JSON forRequest:request error:nil]; + completionBlock(JSON, nil); + } + } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id data) { + if([self executeRequestWithId:requestId]) { + if(self.logServerResponses) + [self logResponse:nil forRequest:request error:error]; + completionBlock(nil, error); + } + } + ]; + + [self enqueueHTTPRequestOperation:op]; + return requestId; +} + +-(NSNumber*) stringWithCompletionBlock:(NSString*) path + method:(NSString*) method + queryParams:(NSDictionary*) queryParams + body:(id) body + headerParams:(NSDictionary*) headerParams + requestContentType:(NSString*) requestContentType + responseContentType:(NSString*) responseContentType + completionBlock:(void (^)(NSString*, NSError *))completionBlock { + AFHTTPClient *client = self; + client.parameterEncoding = AFJSONParameterEncoding; + + NSMutableURLRequest * request = nil; + + if ([body isKindOfClass:[SWGFile class]]){ + SWGFile * file = (SWGFile*) body; + + request = [self multipartFormRequestWithMethod:@"POST" + path:path + parameters:nil + constructingBodyWithBlock: ^(id formData) { + [formData appendPartWithFileData:[file data] + name:@"image" + fileName:[file name] + mimeType:[file mimeType]]; + }]; + } + else { + request = [self requestWithMethod:method + path:[self pathWithQueryParamsToString:path queryParams:queryParams] + parameters:body]; + } + + BOOL hasHeaderParams = false; + if(headerParams != nil && [headerParams count] > 0) + hasHeaderParams = true; + if(offlineState) { + NSLog(@"%@ cache forced", path); + [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad]; + } + else if(!hasHeaderParams && [method isEqualToString:@"GET"] && cacheEnabled) { + NSLog(@"%@ cache enabled", path); + [request setCachePolicy:NSURLRequestUseProtocolCachePolicy]; + } + else { + NSLog(@"%@ cache disabled", path); + [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]; + } + + if(body != nil) { + if([body isKindOfClass:[NSDictionary class]]){ + [request setValue:requestContentType forHTTPHeaderField:@"Content-Type"]; + } + else if ([body isKindOfClass:[SWGFile class]]){} + else { + NSAssert(false, @"unsupported post type!"); + } + } + if(headerParams != nil){ + for(NSString * key in [headerParams keyEnumerator]){ + [request setValue:[headerParams valueForKey:key] forHTTPHeaderField:key]; + } + } + [request setValue:[headerParams valueForKey:responseContentType] forHTTPHeaderField:@"Accept"]; + + // Always disable cookies! + [request setHTTPShouldHandleCookies:NO]; + + NSNumber* requestId = [SWGApiClient queueRequest]; + AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request]; + [op setCompletionBlockWithSuccess: + ^(AFHTTPRequestOperation *resp, + id responseObject) { + NSString *response = [resp responseString]; + if([self executeRequestWithId:requestId]) { + if(self.logServerResponses) + [self logResponse:responseObject forRequest:request error:nil]; + completionBlock(response, nil); + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if([self executeRequestWithId:requestId]) { + if(self.logServerResponses) + [self logResponse:nil forRequest:request error:error]; + completionBlock(nil, error); + } + }]; + + [self enqueueHTTPRequestOperation:op]; + return requestId; +} + +@end diff --git a/modules/swagger-codegen/src/main/resources/objc/SWGDate.h b/modules/swagger-codegen/src/main/resources/objc/SWGDate.h new file mode 100644 index 00000000000..2c6c7cfe01b --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/objc/SWGDate.h @@ -0,0 +1,12 @@ +#import +#import "SWGObject.h" + +@interface SWGDate : SWGObject { +@private + NSDate *_date; +} +@property(nonatomic, readonly) NSDate* date; + +- (id) initWithValues: (NSString*)input; +-(NSString*) toString; +@end \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/objc/SWGDate.m b/modules/swagger-codegen/src/main/resources/objc/SWGDate.m new file mode 100644 index 00000000000..07a1405626b --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/objc/SWGDate.m @@ -0,0 +1,34 @@ +#import "SWGDate.h" + +@implementation SWGDate + +@synthesize date = _date; + +- (id) initWithValues:(NSString*)input { + if([input isKindOfClass:[NSString class]]){ + NSDateFormatter* df = [NSDateFormatter new]; + NSLocale *locale = [[NSLocale new] + initWithLocaleIdentifier:@"en_US_POSIX"]; + [df setLocale:locale]; + [df setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"]; + + _date = [df dateFromString:input]; + } + else if([input isKindOfClass:[NSNumber class]]) { + NSTimeInterval interval = [input doubleValue]; + _date = [[NSDate alloc] initWithTimeIntervalSince1970:interval]; + } + return self; +} + +-(NSString*) toString { + NSDateFormatter* df = [NSDateFormatter new]; + NSLocale *locale = [[NSLocale new] + initWithLocaleIdentifier:@"en_US_POSIX"]; + [df setLocale:locale]; + [df setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"]; + + return [df stringFromDate:_date]; +} + +@end \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/objc/SWGFile.h b/modules/swagger-codegen/src/main/resources/objc/SWGFile.h new file mode 100644 index 00000000000..fe6e81c289d --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/objc/SWGFile.h @@ -0,0 +1,13 @@ +#import + +@interface SWGFile : NSObject + +@property(nonatomic, readonly) NSString* name; +@property(nonatomic, readonly) NSString* mimeType; +@property(nonatomic, readonly) NSData* data; + +- (id) initWithNameData: (NSString*) filename + mimeType: (NSString*) mimeType + data: (NSData*) data; + + @end \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/objc/SWGFile.m b/modules/swagger-codegen/src/main/resources/objc/SWGFile.m new file mode 100644 index 00000000000..42552767af4 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/objc/SWGFile.m @@ -0,0 +1,26 @@ +#import "SWGFile.h" + +@implementation SWGFile + +@synthesize name = _name; +@synthesize mimeType = _mimeType; +@synthesize data = _data; + +- (id) init { + self = [super init]; + return self; +} + +- (id) initWithNameData: (NSString*) filename + mimeType: (NSString*) fileMimeType + data: (NSData*) data { + self = [super init]; + if(self) { + _name = filename; + _mimeType = fileMimeType; + _data = data; + } + return self; +} + +@end \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/objc/SWGObject.h b/modules/swagger-codegen/src/main/resources/objc/SWGObject.h new file mode 100644 index 00000000000..031bae69279 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/objc/SWGObject.h @@ -0,0 +1,6 @@ +#import + +@interface SWGObject : NSObject +- (id) initWithValues:(NSDictionary*)dict; +- (NSDictionary*) asDictionary; +@end diff --git a/modules/swagger-codegen/src/main/resources/objc/SWGObject.m b/modules/swagger-codegen/src/main/resources/objc/SWGObject.m new file mode 100644 index 00000000000..9b37b3592b1 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/objc/SWGObject.m @@ -0,0 +1,17 @@ +#import "SWGObject.h" + +@implementation SWGObject + +- (id) initWithValues:(NSDictionary*)dict { + return self; +} + +- (NSDictionary*) asDictionary{ + return [NSDictionary init]; +} + +- (NSString*)description { + return [NSString stringWithFormat:@"%@ %@", [super description], [self asDictionary]]; +} + +@end diff --git a/modules/swagger-codegen/src/main/resources/objc/api-body.mustache b/modules/swagger-codegen/src/main/resources/objc/api-body.mustache new file mode 100644 index 00000000000..22e2262668b --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/objc/api-body.mustache @@ -0,0 +1,234 @@ +{{#operations}} +#import "{{classname}}.h" +#import "SWGFile.h" +#import "SWGApiClient.h" +{{#imports}}#import "{{import}}.h" +{{/imports}} +{{newline}} + + +@implementation {{classname}} +static NSString * basePath = @"{{basePath}}"; + ++({{classname}}*) apiWithHeader:(NSString*)headerValue key:(NSString*)key { + static {{classname}}* singletonAPI = nil; + + if (singletonAPI == nil) { + singletonAPI = [[{{classname}} alloc] init]; + [singletonAPI addHeader:headerValue forKey:key]; + } + return singletonAPI; +} + ++(void) setBasePath:(NSString*)path { + basePath = path; +} + ++(NSString*) getBasePath { + return basePath; +} + +-(SWGApiClient*) apiClient { + return [SWGApiClient sharedClientFromPool:basePath]; +} + +-(void) addHeader:(NSString*)value forKey:(NSString*)key { + [[self apiClient] setHeaderValue:value forKey:key]; +} + +-(id) init { + self = [super init]; + [self apiClient]; + return self; +} + +-(void) setHeaderValue:(NSString*) value + forKey:(NSString*)key { + [[self apiClient] setHeaderValue:value forKey:key]; +} + +-(unsigned long) requestQueueSize { + return [SWGApiClient requestQueueSize]; +} + + +{{#operation}} +-(NSNumber*) {{nickname}}WithCompletionBlock{{^allParams}}: {{/allParams}}{{#allParams}}{{#secondaryParam}} + {{paramName}}{{/secondaryParam}}:({{{dataType}}}) {{paramName}}{{newline}} {{/allParams}} + {{#returnBaseType}}{{#hasParams}}completionHandler: {{/hasParams}}(void (^)({{returnType}} output, NSError* error))completionBlock{{/returnBaseType}} + {{^returnBaseType}}{{#hasParams}}completionHandler: {{/hasParams}}(void (^)(NSError* error))completionBlock{{/returnBaseType}} { + + id m_body = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}nil{{/bodyParam}}; + NSMutableString* requestUrl = [NSMutableString stringWithFormat:@"%@{{path}}", basePath]; + + // remove format in URL if needed + if ([requestUrl rangeOfString:@".{format}"].location != NSNotFound) + [requestUrl replaceCharactersInRange: [requestUrl rangeOfString:@".{format}"] withString:@".json"]; + + {{#pathParams}}[requestUrl replaceCharactersInRange: [requestUrl rangeOfString:[NSString stringWithFormat:@"%@%@%@", @"{", @"{{baseName}}", @"}"]] withString: [SWGApiClient escape:{{paramName}}]]; + {{/pathParams}} + + NSString* requestContentType = @"application/json"; + NSString* responseContentType = @"application/json"; + + NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; + {{#queryParams}}if({{paramName}} != nil) + queryParams[@"{{baseName}}"] = {{paramName}};{{/queryParams}} + NSMutableDictionary* headerParams = [[NSMutableDictionary alloc] init]; + {{#headerParams}}if({{paramName}} != nil) + headerParams[@"{{baseName}}"] = {{paramName}};{{/headerParams}} + + id bodyDictionary = nil; + {{#bodyParam}} + if(m_body != nil && [m_body isKindOfClass:[NSArray class]]){ + NSMutableArray * objs = [[NSMutableArray alloc] init]; + for (id dict in (NSArray*)m_body) { + if([dict respondsToSelector:@selector(asDictionary)]) { + [objs addObject:[(SWGObject*)dict asDictionary]]; + } + else{ + [objs addObject:dict]; + } + } + bodyDictionary = objs; + } + else if([m_body respondsToSelector:@selector(asDictionary)]) { + bodyDictionary = [(SWGObject*)m_body asDictionary]; + } + else if([m_body isKindOfClass:[NSString class]]) { + // convert it to a dictionary + NSError * error; + NSString * str = (NSString*)m_body; + NSDictionary *JSON = + [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] + options:NSJSONReadingMutableContainers + error:&error]; + bodyDictionary = JSON; + } + else if([m_body isKindOfClass: [SWGFile class]]) { + requestContentType = @"form-data"; + bodyDictionary = m_body; + } + else{ + NSLog(@"don't know what to do with %@", m_body); + } + + {{/bodyParam}} + + {{#requiredParamCount}} + {{#requiredParams}} + if({{paramName}} == nil) { + // error + } + {{/requiredParams}} + {{/requiredParamCount}} + + SWGApiClient* client = [SWGApiClient sharedClientFromPool:basePath]; + + {{#returnContainer}} + return [client dictionary: requestUrl + method: @"{{httpMethod}}" + queryParams: queryParams + body: bodyDictionary + headerParams: headerParams + requestContentType: requestContentType + responseContentType: responseContentType + completionBlock: ^(NSDictionary *data, NSError *error) { + if (error) { + {{#returnBaseType}}completionBlock(nil, error);{{/returnBaseType}} + {{^returnBaseType}}completionBlock(error);{{/returnBaseType}} + return; + } + + {{#returnBaseType}} + if([data isKindOfClass:[NSArray class]]){ + NSMutableArray * objs = [[NSMutableArray alloc] initWithCapacity:[data count]]; + for (NSDictionary* dict in (NSArray*)data) { + {{#returnTypeIsPrimitive}} + // {{#instantiationType}}NSClassFromString(@"{{{instantiationType}}}"){{/instantiationType}}{{^instantiationType}}{{{returnBaseType}}}{{/instantiationType}}{{newline}} + {{returnBaseType}}* d = [[{{#instantiationType}}NSClassFromString(@"{{{instantiationType}}}") {{/instantiationType}}{{^instantiationType}}{{{returnBaseType}}} {{/instantiationType}} alloc]initWithString: data]; + {{/returnTypeIsPrimitive}} + {{^returnTypeIsPrimitive}} + {{{returnBaseType}}}* d = [[{{#instantiationType}}NSClassFromString(@"{{{instantiationType}}}") {{/instantiationType}}{{^instantiationType}}{{{returnBaseType}}} {{/instantiationType}} alloc]initWithValues: dict]; + {{/returnTypeIsPrimitive}} + [objs addObject:d]; + } + completionBlock(objs, nil); + } + {{#returnSimpleType}} + {{#returnTypeIsPrimitive}}{{#returnBaseType}}completionBlock( [[{{#instantiationType}}NSClassFromString(@"{{{instantiationType}}}") {{/instantiationType}}{{^instantiationType}}{{{returnBaseType}}} {{/instantiationType}} alloc]initWithString: data], nil;{{/returnBaseType}} + {{/returnTypeIsPrimitive}} + {{^returnTypeIsPrimitive}} + {{#returnBaseType}}completionBlock( [[{{#instantiationType}}NSClassFromString(@"{{{instantiationType}}}") {{/instantiationType}}{{^instantiationType}}{{{returnBaseType}}} {{/instantiationType}} alloc]initWithValues: data], nil);{{/returnBaseType}} + {{/returnTypeIsPrimitive}} + {{/returnSimpleType}} + + {{/returnBaseType}} + }]; + {{/returnContainer}} + + {{#returnSimpleType}} + {{#returnTypeIsPrimitive}} + {{#returnBaseType}} + return [client stringWithCompletionBlock: requestUrl + method: @"{{httpMethod}}" + queryParams: queryParams + body: bodyDictionary + headerParams: headerParams + requestContentType: requestContentType + responseContentType: responseContentType + completionBlock: ^(NSString *data, NSError *error) { + if (error) { + completionBlock(nil, error); + return; + } + {{returnBaseType}} *result = data ? [[{{#instantiationType}}NSClassFromString(@"{{{instantiationType}}}") {{/instantiationType}}{{^instantiationType}}{{{returnBaseType}}} {{/instantiationType}} alloc]initWithString: data] : nil; + completionBlock(result, nil); + }];{{/returnBaseType}} + {{^returnBaseType}} + return [client stringWithCompletionBlock:requestUrl + method:@"{{httpMethod}}" + queryParams:queryParams + body:bodyDictionary + headerParams:headerParams + requestContentType: requestContentType + responseContentType: responseContentType + completionBlock:^(NSString *data, NSError *error) { + if (error) { + completionBlock(error); + return; + } + completionBlock(nil); + }]; + {{/returnBaseType}}{{/returnTypeIsPrimitive}} + {{#returnBaseType}}{{^returnTypeIsPrimitive}} + return [client dictionary:requestUrl + method:@"{{httpMethod}}" + queryParams:queryParams + body:bodyDictionary + headerParams:headerParams + requestContentType:requestContentType + responseContentType:responseContentType + completionBlock:^(NSDictionary *data, NSError *error) { + if (error) { + {{#returnBaseType}}completionBlock(nil, error);{{/returnBaseType}} + {{^returnBaseType}}completionBlock(error);{{/returnBaseType}} + return; + } + {{#returnBaseType}} + {{returnBaseType}} *result = nil; + if (data) { + result = [[{{#instantiationType}}NSClassFromString(@"{{{instantiationType}}}") {{/instantiationType}}{{^instantiationType}}{{{returnBaseType}}} {{/instantiationType}} alloc]initWithValues: data]; + } + {{#returnBaseType}}completionBlock(result , nil);{{/returnBaseType}} + {{/returnBaseType}} + }]; + {{/returnTypeIsPrimitive}}{{/returnBaseType}}{{/returnSimpleType}} +{{newline}} +} + +{{/operation}} + +{{newline}} +{{/operations}} +@end \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/objc/api-header.mustache b/modules/swagger-codegen/src/main/resources/objc/api-header.mustache new file mode 100644 index 00000000000..7bc55a0fade --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/objc/api-header.mustache @@ -0,0 +1,29 @@ +#import +{{#imports}}#import "{{import}}.h" +{{/imports}} +{{newline}} + +{{#operations}} +@interface {{classname}}: NSObject + +-(void) addHeader:(NSString*)value forKey:(NSString*)key; +-(unsigned long) requestQueueSize; ++({{classname}}*) apiWithHeader:(NSString*)headerValue key:(NSString*)key; ++(void) setBasePath:(NSString*)basePath; ++(NSString*) getBasePath; +{{#operation}} +/** + + {{#summary}}{{{summary}}}{{/summary}} + {{#notes}}{{{notes}}}{{/notes}} + + {{#allParams}}@param {{paramName}} {{description}} + {{/allParams}} + */ +-(NSNumber*) {{nickname}}WithCompletionBlock {{^allParams}}:{{/allParams}}{{#allParams}}{{#secondaryParam}} + {{paramName}}{{/secondaryParam}}: ({{{dataType}}}) {{paramName}}{{/allParams}} +{{#returnBaseType}}{{#hasParams}} completionHandler: {{/hasParams}}(void (^)({{returnType}} output, NSError* error))completionBlock;{{/returnBaseType}} +{{^returnBaseType}}{{#hasParams}} completionHandler: {{/hasParams}}(void (^)(NSError* error))completionBlock;{{/returnBaseType}} +{{/operation}} +{{/operations}} +@end \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/objc/model-body.mustache b/modules/swagger-codegen/src/main/resources/objc/model-body.mustache new file mode 100644 index 00000000000..43555d48a19 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/objc/model-body.mustache @@ -0,0 +1,94 @@ +{{#models}} +{{#model}} +#import "SWGDate.h" +#import "{{classname}}.h" + +@implementation {{classname}}{{#parent}}: {{parent}}{{/parent}} + +{{#hasVars}} +-(id){{#vars}}{{name}}: ({{datatype}}) {{name}}{{^hasMore}} { {{/hasMore}} + {{/vars}} + {{#vars}}_{{name}} = {{name}}; + {{/vars}} + return self; +} +{{/hasVars}} +-(id) initWithValues:(NSDictionary*)dict +{ + self = [super init]; + if(self) { + {{#vars}}{{#isPrimitiveType}}_{{name}} = dict[@"{{baseName}}"];{{/isPrimitiveType}} + {{#complexType}}id {{name}}_dict = dict[@"{{baseName}}"];{{#isContainer}} + if([{{name}}_dict isKindOfClass:[NSArray class]]) { + NSMutableArray * objs = [[NSMutableArray alloc] initWithCapacity:[(NSArray*){{name}}_dict count]]; + if([(NSArray*){{name}}_dict count] > 0) { + for (NSDictionary* dict in (NSArray*){{name}}_dict) { + {{{complexType}}}* d = [[{{#instantiationType}}NSClassFromString(@"{{{instantiationType}}}") {{/instantiationType}}{{^instantiationType}}{{{complexType}}} {{/instantiationType}} alloc] initWithValues:dict]; + [objs addObject:d]; + } + _{{{name}}} = [[NSArray alloc] initWithArray:objs]; + } + else { + _{{name}} = [[NSArray alloc] init]; + } + } + else { + _{{name}} = [[NSArray alloc] init]; + }{{/isContainer}} + {{#isNotContainer}}if({{name}}_dict != nil) + _{{name}} = [[{{#instantiationType}}NSClassFromString(@"{{{instantiationType}}}") {{/instantiationType}}{{^instantiationType}}{{{complexType}}} {{/instantiationType}} alloc]initWithValues:{{name}}_dict]; + {{/isNotContainer}} + {{/complexType}}{{/vars}} + } + return self; +} + +-(NSDictionary*) asDictionary { + NSMutableDictionary* dict = [[NSMutableDictionary alloc] init]; + {{#vars}}{{#complexType}} + if(_{{name}} != nil){ + {{#isContainer}} + if([_{{name}} isKindOfClass:[NSArray class]]){ + NSMutableArray * array = [[NSMutableArray alloc] init]; + for( {{complexType}} *{{name}} in _{{name}}) { + [array addObject:[(SWGObject*){{name}} asDictionary]]; + } + dict[@"{{name}}"] = array; + } + {{/isContainer}} + {{^isContainer}} + if(_{{name}} && [_{{name}} isKindOfClass:[SWGDate class]]) { + NSString * dateString = [(SWGDate*)_{{name}} toString]; + if(dateString){ + dict[@"{{name}}"] = dateString; + } + } + else { + if(_{{name}} != nil) + dict[@"{{baseName}}"] = [(SWGObject*)_{{name}} asDictionary]; + } + {{/isContainer}} + } + {{/complexType}} + {{#isPrimitiveType}}{{#isNotContainer}} + if(_{{name}} != nil) + dict[@"{{baseName}}"] = _{{name}}; + {{/isNotContainer}} + {{#isContainer}} + if(_{{name}} != nil) { + if([_{{name}} isKindOfClass:[NSArray class]]) { + dict[@"_{{name}}"] = [[NSArray alloc] initWithArray: (NSArray*) _{{name}} copyItems:true]; + } + else if([_{{name}} isKindOfClass:[NSDictionary class]]) { + dict[@"{{name}}"] = [[NSDictionary alloc] initWithDictionary:(NSDictionary*)_{{name}} copyItems:true]; + } + } + {{/isContainer}} + {{/isPrimitiveType}}{{/vars}} + NSDictionary* output = [dict copy]; + return output; +} + +{{/model}} +@end +{{/models}} diff --git a/modules/swagger-codegen/src/main/resources/objc/model-header.mustache b/modules/swagger-codegen/src/main/resources/objc/model-header.mustache new file mode 100644 index 00000000000..e8dc61316e0 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/objc/model-header.mustache @@ -0,0 +1,24 @@ +#import +#import "SWGObject.h" +{{#imports}}#import "{{import}}.h" +{{/imports}} +{{newline}} +{{#models}} +{{#model}} + +@interface {{classname}} : {{^parent}}SWGObject{{/parent}}{{#parent}}{{parent}}{{/parent}} + +{{#vars}} +@property(nonatomic) {{datatype}} {{name}}; {{#description}}/* {{{description}}} {{#isNotRequired}}[optional]{{/isNotRequired}} */{{/description}}{{newline}} +{{/vars}} +{{#hasVars}} +- (id) {{#vars}}{{name}}: ({{datatype}}) {{name}}{{#hasMore}} + {{/hasMore}}{{^hasMore}};{{/hasMore}} + {{/vars}} +{{/hasVars}} +- (id) initWithValues: (NSDictionary*)dict; +- (NSDictionary*) asDictionary; +{{newline}} +@end +{{/model}} +{{/models}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/php/Swagger.mustache b/modules/swagger-codegen/src/main/resources/php/Swagger.mustache new file mode 100644 index 00000000000..7e1f24f49b6 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/php/Swagger.mustache @@ -0,0 +1,231 @@ +apiKey = $apiKey; + $this->apiServer = $apiServer; + } + + + /** + * @param string $resourcePath path to method endpoint + * @param string $method method to call + * @param array $queryParams parameters to be place in query URL + * @param array $postData parameters to be placed in POST body + * @param array $headerParams parameters to be place in request header + * @return mixed + */ + public function callAPI($resourcePath, $method, $queryParams, $postData, + $headerParams) { + + $headers = array(); + + # Allow API key from $headerParams to override default + $added_api_key = False; + if ($headerParams != null) { + foreach ($headerParams as $key => $val) { + $headers[] = "$key: $val"; + if ($key == 'api_key') { + $added_api_key = True; + } + } + } + if (! $added_api_key) { + $headers[] = "api_key: " . $this->apiKey; + } + + if (is_object($postData) or is_array($postData)) { + $postData = json_encode($this->sanitizeForSerialization($postData)); + } + + $url = $this->apiServer . $resourcePath; + + $curl = curl_init(); + curl_setopt($curl, CURLOPT_TIMEOUT, 5); + // return the result on success, rather than just TRUE + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + + if (! empty($queryParams)) { + $url = ($url . '?' . http_build_query($queryParams)); + } + + if ($method == self::$POST) { + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); + } else if ($method == self::$PUT) { + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT"); + curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); + } else if ($method == self::$DELETE) { + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE"); + curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); + } else if ($method != self::$GET) { + throw new Exception('Method ' . $method . ' is not recognized.'); + } + curl_setopt($curl, CURLOPT_URL, $url); + + // Make the request + $response = curl_exec($curl); + $response_info = curl_getinfo($curl); + + // Handle the response + if ($response_info['http_code'] == 0) { + throw new Exception("TIMEOUT: api call to " . $url . + " took more than 5s to return" ); + } else if ($response_info['http_code'] == 200) { + $data = json_decode($response); + } else if ($response_info['http_code'] == 401) { + throw new Exception("Unauthorized API request to " . $url . + ": ".json_decode($response)->message ); + } else if ($response_info['http_code'] == 404) { + $data = null; + } else { + throw new Exception("Can't connect to the api: " . $url . + " response code: " . + $response_info['http_code']); + } + return $data; + } + + /** + * Build a JSON POST object + */ + protected function sanitizeForSerialization($data) + { + if (is_scalar($data) || null === $data) { + $sanitized = $data; + } else if ($data instanceof \DateTime) { + $sanitized = $data->format(\DateTime::ISO8601); + } else if (is_array($data)) { + foreach ($data as $property => $value) { + $data[$property] = $this->sanitizeForSerialization($value); + } + $sanitized = $data; + } else if (is_object($data)) { + $values = array(); + foreach (array_keys($data::$swaggerTypes) as $property) { + $values[$property] = $this->sanitizeForSerialization($data->$property); + } + $sanitized = $values; + } else { + $sanitized = (string)$data; + } + + return $sanitized; + } + + /** + * Take value and turn it into a string suitable for inclusion in + * the path, by url-encoding. + * @param string $value a string which will be part of the path + * @return string the serialized object + */ + public static function toPathValue($value) { + return rawurlencode($value); + } + + /** + * Take value and turn it into a string suitable for inclusion in + * the query, by imploding comma-separated if it's an object. + * If it's a string, pass through unchanged. It will be url-encoded + * later. + * @param object $object an object to be serialized to a string + * @return string the serialized object + */ + public static function toQueryValue($object) { + if (is_array($object)) { + return implode(',', $object); + } else { + return $object; + } + } + + /** + * Just pass through the header value for now. Placeholder in case we + * find out we need to do something with header values. + * @param string $value a string which will be part of the header + * @return string the header string + */ + public static function toHeaderValue($value) { + return $value; + } + + /** + * Deserialize a JSON string into an object + * + * @param object $object object or primitive to be deserialized + * @param string $class class name is passed as a string + * @return object an instance of $class + */ + + public static function deserialize($data, $class) + { + if (null === $data) { + $deserialized = null; + } elseif (substr($class, 0, 4) == 'map[') { + $inner = substr($class, 4, -1); + $values = array(); + if(strrpos($inner, ",") !== false) { + $subClass = explode(',', $inner, 2)[1]; + foreach ($data as $key => $value) { + $values[] = array($key => self::deserialize($value, $subClass)); + } + } + $deserialized = $values; + } elseif (substr($class, 0, 6) == 'array[') { + $subClass = substr($class, 6, -1); + foreach ($data as $key => $value) { + $values[] = self::deserialize($value, $subClass); + } + $deserialized = $values; + } elseif ($class == 'DateTime') { + $deserialized = new \DateTime($data); + } elseif (in_array($class, array('string', 'int', 'float', 'bool'))) { + settype($data, $class); + $deserialized = $data; + } else { + $instance = new $class(); + foreach ($instance::$swaggerTypes as $property => $type) { + if (isset($data->$property)) { + $instance->$property = self::deserialize($data->$property, $type); + } + } + $deserialized = $instance; + } + + return $deserialized; + } + +} + diff --git a/modules/swagger-codegen/src/main/resources/php/api.mustache b/modules/swagger-codegen/src/main/resources/php/api.mustache new file mode 100644 index 00000000000..82ea7174032 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/php/api.mustache @@ -0,0 +1,86 @@ +apiClient = $apiClient; + } + + {{#operation}} + /** + * {{{nickname}}} + * + * {{{summary}}} + {{#allParams}}* {{paramName}}, {{dataType}}: {{description}} {{^optional}}(required){{/optional}}{{#optional}}(optional){{/optional}} + * {{/allParams}} + * @return {{{returnType}}} + */ + + public function {{nickname}}({{#allParams}}${{paramName}}{{#optional}}=null{{/optional}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) { + + // parse inputs + $resourcePath = "{{path}}"; + $resourcePath = str_replace("{format}", "json", $resourcePath); + $method = "{{httpMethod}}"; + $queryParams = array(); + $headerParams = array(); + $headerParams['Accept'] = '{{#produces}}{{mediaType}}{{#hasMore}},{{/hasMore}}{{/produces}}'; + $headerParams['Content-Type'] = '{{#consumes}}{{mediaType}}{{#hasMore}},{{/hasMore}}{{/consumes}}'; + + {{#queryParams}}// query params + if(${{paramName}} != null) { + $queryParams['{{paramName}}'] = $this->apiClient->toQueryValue(${{paramName}}); + }{{/queryParams}} + {{#headerParams}}// header params + if(${{paramName}} != null) { + $headerParams['{{paramName}}'] = $this->apiClient->toHeaderValue(${{paramName}}); + }{{/headerParams}} + {{#pathParams}}// path params + if(${{paramName}} != null) { + $resourcePath = str_replace("{" . "{{paramName}}" . "}", + $this->apiClient->toPathValue(${{paramName}}), $resourcePath); + }{{/pathParams}} + {{#bodyParams}}// body params + $body = null; + if (isset(${{paramName}})) { + $body = ${{paramName}}; + } + {{/bodyParams}} + + // make the API Call + $response = $this->apiClient->callAPI($resourcePath, $method, + $queryParams, $body, + $headerParams); + + {{#returnType}}if(! $response) { + return null; + } + + $responseObject = $this->apiClient->deserialize($response, + '{{returnType}}'); + return $responseObject;{{/returnType}} + } + {{/operation}} +{{newline}} +{{/operations}} +} diff --git a/modules/swagger-codegen/src/main/resources/php/model.mustache b/modules/swagger-codegen/src/main/resources/php/model.mustache new file mode 100644 index 00000000000..cc98fa352f3 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/php/model.mustache @@ -0,0 +1,40 @@ + '{{{datatype}}}'{{#hasMore}}, + {{/hasMore}}{{/vars}} + ); + + {{#vars}}{{#description}} + /** + * {{{description}}} + */{{/description}} + public ${{name}}; /* {{{datatype}}} */{{/vars}} +} +{{/model}} +{{/models}} diff --git a/modules/swagger-codegen/src/main/resources/python/__init__.mustache b/modules/swagger-codegen/src/main/resources/python/__init__.mustache new file mode 100644 index 00000000000..4b41ee706c7 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/python/__init__.mustache @@ -0,0 +1,9 @@ +#!/usr/bin/env python +"""Add all of the modules in the current directory to __all__""" +import os + +__all__ = [] + +for module in os.listdir(os.path.dirname(__file__)): + if module != '__init__.py' and module[-3:] == '.py': + __all__.append(module[:-3]) diff --git a/modules/swagger-codegen/src/main/resources/python/api.mustache b/modules/swagger-codegen/src/main/resources/python/api.mustache new file mode 100644 index 00000000000..1650effd991 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/python/api.mustache @@ -0,0 +1,98 @@ +#!/usr/bin/env python +""" +WordAPI.py +Copyright 2014 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. + +NOTE: This class is auto generated by the swagger code generator program. Do not edit the class manually. +""" +import sys +import os + +from models import * + + +{{#operations}} +class {{classname}}(object): + + def __init__(self, apiClient): + self.apiClient = apiClient + + {{newline}} + {{#operation}} + def {{nickname}}(self, {{#requiredParams}}{{paramName}}{{#defaultValue}} = None{{/defaultValue}}, {{/requiredParams}}**kwargs): + """{{summary}} + + Args: + {{#allParams}} + {{paramName}}, {{dataType}}: {{description}} {{^optional}}(required){{/optional}}{{#optional}}(optional){{/optional}} + {{newline}} + {{/allParams}} + {{newline}} + Returns: {{returnType}} + """ + + allParams = [{{#allParams}}'{{paramName}}'{{#hasMore}}, {{/hasMore}}{{/allParams}}] + + params = locals() + for (key, val) in params['kwargs'].iteritems(): + if key not in allParams: + raise TypeError("Got an unexpected keyword argument '%s' to method {{nickname}}" % key) + params[key] = val + del params['kwargs'] + + resourcePath = '{{path}}' + resourcePath = resourcePath.replace('{format}', 'json') + method = '{{httpMethod}}' + + queryParams = {} + headerParams = {} + $headerParams['Accept'] = '{{#produces}}{{mediaType}}{{#hasMore}},{{/hasMore}}{{/produces}}'; + $headerParams['Content-Type'] = '{{#consumes}}{{mediaType}}{{#hasMore}},{{/hasMore}}{{/consumes}}'; + + {{#queryParams}} + if ('{{paramName}}' in params): + queryParams['{{paramName}}'] = self.apiClient.toPathValue(params['{{paramName}}']) + {{/queryParams}} + + {{#headerParams}} + if ('{{paramName}}' in params): + headerParams['{{paramName}}'] = params['{{paramName}}'] + {{/headerParams}} + + {{#pathParams}} + if ('{{paramName}}' in params): + replacement = str(self.apiClient.toPathValue(params['{{paramName}}'])) + resourcePath = resourcePath.replace('{' + '{{baseName}}' + '}', + replacement) + {{/pathParams}} + + postData = (params['body'] if 'body' in params else None) + + response = self.apiClient.callAPI(resourcePath, method, queryParams, + postData, headerParams) + + {{#returnType}} + if not response: + return None + + responseObject = self.apiClient.deserialize(response, '{{returnType}}') + return responseObject + {{/returnType}} + {{newline}} + {{newline}} + {{/operation}} +{{newline}} +{{/operations}} +{{newline}} diff --git a/modules/swagger-codegen/src/main/resources/python/model.mustache b/modules/swagger-codegen/src/main/resources/python/model.mustache new file mode 100644 index 00000000000..39547c90050 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/python/model.mustache @@ -0,0 +1,40 @@ +#!/usr/bin/env python +""" +Copyright 2014 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. +""" +{{#models}} +{{#model}} + +class {{classname}}: + """NOTE: This class is auto generated by the swagger code generator program. + Do not edit the class manually.""" + + + def __init__(self): + self.swaggerTypes = { + {{#vars}} + '{{name}}': '{{{datatype}}}'{{#hasMore}}, + {{/hasMore}} + {{/vars}}{{newline}} + } + + + {{#vars}} + {{#description}}#{{description}} + {{/description}} + self.{{name}} = None # {{{datatype}}} + {{/vars}} +{{/model}} +{{/models}} diff --git a/modules/swagger-codegen/src/main/resources/python/swagger.mustache b/modules/swagger-codegen/src/main/resources/python/swagger.mustache new file mode 100644 index 00000000000..e62f854c7bf --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/python/swagger.mustache @@ -0,0 +1,208 @@ +#!/usr/bin/env python +"""Wordnik.com's Swagger generic API client. This client handles the client- +server communication, and is invariant across implementations. Specifics of +the methods and models for each application are generated from the Swagger +templates.""" + +import sys +import os +import re +import urllib +import urllib2 +import httplib +import json +import datetime + +from models import * + + +class ApiClient: + """Generic API client for Swagger client library builds""" + + def __init__(self, apiKey=None, apiServer=None): + if apiKey == None: + raise Exception('You must pass an apiKey when instantiating the ' + 'APIClient') + self.apiKey = apiKey + self.apiServer = apiServer + self.cookie = None + + def callAPI(self, resourcePath, method, queryParams, postData, + headerParams=None): + + url = self.apiServer + resourcePath + headers = {} + if headerParams: + for param, value in headerParams.iteritems(): + headers[param] = value + + #headers['Content-type'] = 'application/json' + headers['api_key'] = self.apiKey + + if self.cookie: + headers['Cookie'] = self.cookie + + data = None + + if queryParams: + # Need to remove None values, these should not be sent + sentQueryParams = {} + for param, value in queryParams.items(): + if value != None: + sentQueryParams[param] = value + url = url + '?' + urllib.urlencode(sentQueryParams) + + if method in ['GET']: + + #Options to add statements later on and for compatibility + pass + + elif method in ['POST', 'PUT', 'DELETE']: + + if postData: + headers['Content-type'] = 'application/json' + data = self.sanitizeForSerialization(postData) + data = json.dumps(data) + + else: + raise Exception('Method ' + method + ' is not recognized.') + + request = MethodRequest(method=method, url=url, headers=headers, + data=data) + + # Make the request + response = urllib2.urlopen(request) + if 'Set-Cookie' in response.headers: + self.cookie = response.headers['Set-Cookie'] + string = response.read() + + try: + data = json.loads(string) + except ValueError: # PUT requests don't return anything + data = None + + return data + + def toPathValue(self, obj): + """Convert a string or object to a path-friendly value + Args: + obj -- object or string value + Returns: + string -- quoted value + """ + if type(obj) == list: + return urllib.quote(','.join(obj)) + else: + return urllib.quote(str(obj)) + + def sanitizeForSerialization(self, obj): + """Dump an object into JSON for POSTing.""" + + if type(obj) == type(None): + return None + elif type(obj) in [str, int, long, float, bool]: + return obj + elif type(obj) == list: + return [self.sanitizeForSerialization(subObj) for subObj in obj] + elif type(obj) == datetime.datetime: + return obj.isoformat() + else: + if type(obj) == dict: + objDict = obj + else: + objDict = obj.__dict__ + return {key: self.sanitizeForSerialization(val) + for (key, val) in objDict.iteritems() + if key != 'swaggerTypes'} + + if type(postData) == list: + # Could be a list of objects + if type(postData[0]) in safeToDump: + data = json.dumps(postData) + else: + data = json.dumps([datum.__dict__ for datum in postData]) + elif type(postData) not in safeToDump: + data = json.dumps(postData.__dict__) + + def deserialize(self, obj, objClass): + """Derialize a JSON string into an object. + + Args: + obj -- string or object to be deserialized + objClass -- class literal for deserialzied object, or string + of class name + Returns: + object -- deserialized object""" + + # Have to accept objClass as string or actual type. Type could be a + # native Python type, or one of the model classes. + if type(objClass) == str: + if 'list[' in objClass: + match = re.match('list\[(.*)\]', objClass) + subClass = match.group(1) + return [self.deserialize(subObj, subClass) for subObj in obj] + + if (objClass in ['int', 'float', 'long', 'dict', 'list', 'str', 'bool', 'datetime']): + objClass = eval(objClass) + else: # not a native type, must be model class + objClass = eval(objClass + '.' + objClass) + + if objClass in [int, long, float, dict, list, str, bool]: + return objClass(obj) + elif objClass == datetime: + # Server will always return a time stamp in UTC, but with + # trailing +0000 indicating no offset from UTC. So don't process + # last 5 characters. + return datetime.datetime.strptime(obj[:-5], + "%Y-%m-%dT%H:%M:%S.%f") + + instance = objClass() + + for attr, attrType in instance.swaggerTypes.iteritems(): + if obj is not None and attr in obj and type(obj) in [list, dict]: + value = obj[attr] + if attrType in ['str', 'int', 'long', 'float', 'bool']: + attrType = eval(attrType) + try: + value = attrType(value) + except UnicodeEncodeError: + value = unicode(value) + except TypeError: + value = value + setattr(instance, attr, value) + elif (attrType == 'datetime'): + setattr(instance, attr, datetime.datetime.strptime(value[:-5], + "%Y-%m-%dT%H:%M:%S.%f")) + elif 'list[' in attrType: + match = re.match('list\[(.*)\]', attrType) + subClass = match.group(1) + subValues = [] + if not value: + setattr(instance, attr, None) + else: + for subValue in value: + subValues.append(self.deserialize(subValue, + subClass)) + setattr(instance, attr, subValues) + else: + setattr(instance, attr, self.deserialize(value, + objClass)) + + return instance + + +class MethodRequest(urllib2.Request): + + def __init__(self, *args, **kwargs): + """Construct a MethodRequest. Usage is the same as for + `urllib2.Request` except it also takes an optional `method` + keyword argument. If supplied, `method` will be used instead of + the default.""" + + if 'method' in kwargs: + self.method = kwargs.pop('method') + return urllib2.Request.__init__(self, *args, **kwargs) + + def get_method(self): + return getattr(self, 'method', urllib2.Request.get_method(self)) + diff --git a/modules/swagger-codegen/src/main/resources/python3/__init__.mustache b/modules/swagger-codegen/src/main/resources/python3/__init__.mustache new file mode 100644 index 00000000000..4b41ee706c7 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/python3/__init__.mustache @@ -0,0 +1,9 @@ +#!/usr/bin/env python +"""Add all of the modules in the current directory to __all__""" +import os + +__all__ = [] + +for module in os.listdir(os.path.dirname(__file__)): + if module != '__init__.py' and module[-3:] == '.py': + __all__.append(module[:-3]) diff --git a/modules/swagger-codegen/src/main/resources/python3/api.mustache b/modules/swagger-codegen/src/main/resources/python3/api.mustache new file mode 100644 index 00000000000..2d8fbdc29ca --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/python3/api.mustache @@ -0,0 +1,96 @@ +#!/usr/bin/env python +""" +WordAPI.py +Copyright 2014 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. + +NOTE: This class is auto generated by the swagger code generator program. Do not edit the class manually. +""" +import sys +import os + +from .models import * + + +{{#operations}} +class {{classname}}(object): + + def __init__(self, apiClient): + self.apiClient = apiClient + + {{newline}} + {{#operation}} + def {{nickname}}(self, {{#requiredParams}}{{paramName}}{{#defaultValue}} = None{{/defaultValue}}, {{/requiredParams}}**kwargs): + """{{summary}} + + Args: + {{#allParams}} + {{paramName}}, {{dataType}}: {{description}} {{^optional}}(required){{/optional}}{{#optional}}(optional){{/optional}} + {{newline}} + {{/allParams}} + {{newline}} + Returns: {{returnType}} + """ + + allParams = [{{#allParams}}'{{paramName}}'{{#hasMore}}, {{/hasMore}}{{/allParams}}] + + params = locals() + for (key, val) in params['kwargs'].items(): + if key not in allParams: + raise TypeError("Got an unexpected keyword argument '%s' to method {{nickname}}" % key) + params[key] = val + del params['kwargs'] + + resourcePath = '{{path}}' + resourcePath = resourcePath.replace('{format}', 'json') + method = '{{httpMethod}}' + + queryParams = {} + headerParams = {} + + {{#queryParams}} + if ('{{paramName}}' in params): + queryParams['{{paramName}}'] = self.apiClient.toPathValue(params['{{paramName}}']) + {{/queryParams}} + + {{#headerParams}} + if ('{{paramName}}' in params): + headerParams['{{paramName}}'] = params['{{paramName}}'] + {{/headerParams}} + + {{#pathParams}} + if ('{{paramName}}' in params): + replacement = str(self.apiClient.toPathValue(params['{{paramName}}'])) + resourcePath = resourcePath.replace('{' + '{{baseName}}' + '}', + replacement) + {{/pathParams}} + + postData = (params['body'] if 'body' in params else None) + + response = self.apiClient.callAPI(resourcePath, method, queryParams, + postData, headerParams) + + {{#returnType}} + if not response: + return None + + responseObject = self.apiClient.deserialize(response, '{{returnType}}') + return responseObject + {{/returnType}} + {{newline}} + {{newline}} + {{/operation}} +{{newline}} +{{/operations}} +{{newline}} diff --git a/modules/swagger-codegen/src/main/resources/python3/model.mustache b/modules/swagger-codegen/src/main/resources/python3/model.mustache new file mode 100644 index 00000000000..39547c90050 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/python3/model.mustache @@ -0,0 +1,40 @@ +#!/usr/bin/env python +""" +Copyright 2014 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. +""" +{{#models}} +{{#model}} + +class {{classname}}: + """NOTE: This class is auto generated by the swagger code generator program. + Do not edit the class manually.""" + + + def __init__(self): + self.swaggerTypes = { + {{#vars}} + '{{name}}': '{{{datatype}}}'{{#hasMore}}, + {{/hasMore}} + {{/vars}}{{newline}} + } + + + {{#vars}} + {{#description}}#{{description}} + {{/description}} + self.{{name}} = None # {{{datatype}}} + {{/vars}} +{{/model}} +{{/models}} diff --git a/modules/swagger-codegen/src/main/resources/python3/swagger.mustache b/modules/swagger-codegen/src/main/resources/python3/swagger.mustache new file mode 100644 index 00000000000..a01b69794ee --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/python3/swagger.mustache @@ -0,0 +1,203 @@ +#!/usr/bin/env python +"""Wordnik.com's Swagger generic API client. This client handles the client- +server communication, and is invariant across implementations. Specifics of +the methods and models for each application are generated from the Swagger +templates.""" + +import sys +import os +import re +import urllib.request, urllib.error, urllib.parse +import http.client +import json +import datetime + +from .models import * + + +class ApiClient: + """Generic API client for Swagger client library builds""" + + def __init__(self, apiKey=None, apiServer=None): + if apiKey == None: + raise Exception('You must pass an apiKey when instantiating the ' + 'APIClient') + self.apiKey = apiKey + self.apiServer = apiServer + self.cookie = None + + def callAPI(self, resourcePath, method, queryParams, postData, + headerParams=None): + + url = self.apiServer + resourcePath + headers = {} + if headerParams: + for param, value in headerParams.items(): + headers[param] = value + + #headers['Content-type'] = 'application/json' + headers['api_key'] = self.apiKey + + if self.cookie: + headers['Cookie'] = self.cookie + + data = None + + + if queryParams: + # Need to remove None values, these should not be sent + sentQueryParams = {} + for param, value in queryParams.items(): + if value != None: + sentQueryParams[param] = value + url = url + '?' + urllib.parse.urlencode(sentQueryParams) + + if method in ['GET']: + + #Options to add statements later on and for compatibility + pass + + elif method in ['POST', 'PUT', 'DELETE']: + + if postData: + headers['Content-type'] = 'application/json' + data = self.sanitizeForSerialization(postData) + data = json.dumps(data) + + else: + raise Exception('Method ' + method + ' is not recognized.') + + if data: + data = data.encode('utf-8') + + requestParams = MethodRequest(method=method, url=url, + headers=headers, data=data) + + # Make the request + request = urllib.request.urlopen(requestParams) + encoding = request.headers.get_content_charset() + if not encoding: + encoding = 'iso-8859-1' + response = request.read().decode(encoding) + + try: + data = json.loads(response) + except ValueError: # PUT requests don't return anything + data = None + + return data + + def toPathValue(self, obj): + """Convert a string or object to a path-friendly value + Args: + obj -- object or string value + Returns: + string -- quoted value + """ + if type(obj) == list: + return urllib.parse.quote(','.join(obj)) + else: + return urllib.parse.quote(str(obj)) + + def sanitizeForSerialization(self, obj): + """Dump an object into JSON for POSTing.""" + + if type(obj) == type(None): + return None + elif type(obj) in [str, int, float, bool]: + return obj + elif type(obj) == list: + return [self.sanitizeForSerialization(subObj) for subObj in obj] + elif type(obj) == datetime.datetime: + return obj.isoformat() + else: + if type(obj) == dict: + objDict = obj + else: + objDict = obj.__dict__ + return {key: self.sanitizeForSerialization(val) + for (key, val) in objDict.items() + if key != 'swaggerTypes'} + + def deserialize(self, obj, objClass): + """Derialize a JSON string into an object. + + Args: + obj -- string or object to be deserialized + objClass -- class literal for deserialzied object, or string + of class name + Returns: + object -- deserialized object""" + + # Have to accept objClass as string or actual type. Type could be a + # native Python type, or one of the model classes. + if type(objClass) == str: + if 'list[' in objClass: + match = re.match('list\[(.*)\]', objClass) + subClass = match.group(1) + return [self.deserialize(subObj, subClass) for subObj in obj] + + if (objClass in ['int', 'float', 'dict', 'list', 'str', 'bool', 'datetime']): + objClass = eval(objClass) + else: # not a native type, must be model class + objClass = eval(objClass + '.' + objClass) + + if objClass in [int, float, dict, list, str, bool]: + return objClass(obj) + elif objClass == datetime: + # Server will always return a time stamp in UTC, but with + # trailing +0000 indicating no offset from UTC. So don't process + # last 5 characters. + return datetime.datetime.strptime(obj[:-5], + "%Y-%m-%dT%H:%M:%S.%f") + + instance = objClass() + + for attr, attrType in instance.swaggerTypes.items(): + + if attr in obj: + value = obj[attr] + if attrType in ['str', 'int', 'float', 'bool']: + attrType = eval(attrType) + try: + value = attrType(value) + except UnicodeEncodeError: + value = unicode(value) + except TypeError: + value = value + setattr(instance, attr, value) + elif (attrType == 'datetime'): + setattr(instance, attr, datetime.datetime.strptime(value[:-5], + "%Y-%m-%dT%H:%M:%S.%f")) + elif 'list[' in attrType: + match = re.match('list\[(.*)\]', attrType) + subClass = match.group(1) + subValues = [] + if not value: + setattr(instance, attr, None) + else: + for subValue in value: + subValues.append(self.deserialize(subValue, + subClass)) + setattr(instance, attr, subValues) + else: + setattr(instance, attr, self.deserialize(value, + objClass)) + + return instance + + +class MethodRequest(urllib.request.Request): + + def __init__(self, *args, **kwargs): + """Construct a MethodRequest. Usage is the same as for + `urllib.Request` except it also takes an optional `method` + keyword argument. If supplied, `method` will be used instead of + the default.""" + + if 'method' in kwargs: + self.method = kwargs.pop('method') + return urllib.request.Request.__init__(self, *args, **kwargs) + + def get_method(self): + return getattr(self, 'method', urllib.request.Request.get_method(self)) diff --git a/modules/swagger-codegen/src/main/resources/ruby/api.mustache b/modules/swagger-codegen/src/main/resources/ruby/api.mustache new file mode 100644 index 00000000000..b2c546b011e --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/ruby/api.mustache @@ -0,0 +1,85 @@ +require "uri" + +{{#operations}} +class {{classname}} + basePath = "{{basePath}}" + # apiInvoker = APIInvoker + + def self.escapeString(string) + URI.encode(string.to_s) + end + + {{#operation}} + def self.{{nickname}} ({{#allParams}}{{paramName}}{{#defaultValue}} = {{{defaultValue}}}{{/defaultValue}},{{/allParams}} opts={}) + query_param_keys = [{{#queryParams}}:{{paramName}}{{#hasMore}},{{/hasMore}}{{/queryParams}}] + + {{#requiredParamCount}} + + # verify existence of params + {{#requiredParams}} + raise "{{{paramName}}} is required" if {{{paramName}}}.nil? + {{/requiredParams}} + {{/requiredParamCount}} + + # set default values and merge with input + options = { + {{#allParams}} + :{{paramName}} => {{paramName}}{{#hasMore}}, + {{/hasMore}} + {{/allParams}} + }.merge(opts) + + #resource path + path = "{{path}}".sub('{format}','json'){{#pathParams}}.sub('{' + '{{baseName}}' + '}', escapeString({{paramName}})) + {{/pathParams}}{{newline}} + + # pull querystring keys from options + queryopts = options.select do |key,value| + query_param_keys.include? key + end + + {{#headerParams}}headers = { + {{{paramName}}}: {{{paramName}}}, + } + {{/headerParams}} + {{^headerParams}}headers = nil + {{/headerParams}} + + post_body = nil + {{#bodyParam}} + if body != nil + if body.is_a?(Array) + array = Array.new + body.each do |item| + if item.respond_to?("to_body".to_sym) + array.push item.to_body + else + array.push item + end + end + post_body = array + + else + if body.respond_to?("to_body".to_sym) + post_body = body.to_body + else + post_body = body + end + end + end + {{/bodyParam}} + + {{#returnType}} + response = Swagger::Request.new(:{{httpMethod}}, path, {:params=>queryopts,:headers=>headers, :body=>post_body }).make.body + {{#returnContainer}} + response.map {|response|{{/returnContainer}} {{returnBaseType}}.new(response){{#returnContainer}} }{{/returnContainer}} + {{/returnType}} + {{^returnType}} + Swagger::Request.new(:{{httpMethod}}, path, {:params=>queryopts,:headers=>headers, :body=>post_body}).make + {{/returnType}} + {{newline}} + end + +{{/operation}} +end +{{/operations}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/ruby/model.mustache b/modules/swagger-codegen/src/main/resources/ruby/model.mustache new file mode 100644 index 00000000000..c587f12cb49 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/ruby/model.mustache @@ -0,0 +1,41 @@ +{{#models}} + +{{#model}} +class {{classname}} + attr_accessor {{#vars}}:{{{name}}}{{#hasMore}}, {{/hasMore}}{{/vars}}{{newline}} + # :internal => :external + def self.attribute_map + { + {{#vars}} + :{{{name}}} => :{{{baseName}}}{{#hasMore}}, + {{/hasMore}} + {{/vars}}{{newline}} + } + end + + def initialize(attributes = {}) + return if attributes.empty? + # Morph attribute keys into undescored rubyish style + {{#vars}} + if self.class.attribute_map[:"{{{name}}}"] + {{#isContainer}} + if (value = attributes["{{{baseName}}}"]).is_a?(Array) + @{{{name}}} = value{{#complexType}}.map{ |v| {{complexType}}.new(v) }{{/complexType}}{{newline}} + end + {{/isContainer}}{{^isContainer}} + @{{{name}}} = attributes["{{{baseName}}}"] + {{/isContainer}} + end + {{/vars}}{{newline}} + end + + def to_body + body = {} + self.class.attribute_map.each_pair do |key, value| + body[value] = self.send(key) unless self.send(key).nil? + end + body + end +end +{{/model}} +{{/models}} diff --git a/modules/swagger-codegen/src/main/resources/ruby/monkey.mustache b/modules/swagger-codegen/src/main/resources/ruby/monkey.mustache new file mode 100644 index 00000000000..28932890af9 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/ruby/monkey.mustache @@ -0,0 +1,90 @@ +# module Swagger + class Object + + unless Object.method_defined? :blank? + def blank? + respond_to?(:empty?) ? empty? : !self + end + end + + unless Object.method_defined? :present? + def present? + !blank? + end + end + + end + + class String + + unless String.method_defined? :underscore + def underscore + self.gsub(/::/, '/'). + gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). + gsub(/([a-z\d])([A-Z])/,'\1_\2'). + tr("-", "_"). + downcase + end + end + + unless String.method_defined? :camelize + def camelize(first_letter_in_uppercase = true) + if first_letter_in_uppercase != :lower + self.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } + else + self.to_s[0].chr.downcase + camelize(self)[1..-1] + end + end + end + + end + + class Hash + + unless Hash.method_defined? :stringify_keys + def stringify_keys + inject({}) do |options, (key, value)| + options[key.to_s] = value + options + end + end + end + + unless Hash.method_defined? :stringify_keys! + def stringify_keys! + self.replace(self.stringify_keys) + end + end + + unless Hash.method_defined? :symbolize_keys + def symbolize_keys + inject({}) do |options, (key, value)| + options[(key.to_sym rescue key) || key] = value + options + end + end + end + + unless Hash.method_defined? :symbolize_keys! + def symbolize_keys! + self.replace(self.symbolize_keys) + end + end + + unless Hash.method_defined? :symbolize_and_underscore_keys + def symbolize_and_underscore_keys + inject({}) do |options, (key, value)| + options[(key.to_s.underscore.to_sym rescue key) || key] = value + options + end + end + end + + unless Hash.method_defined? :symbolize_and_underscore_keys! + def symbolize_and_underscore_keys! + self.replace(self.symbolize_and_underscore_keys) + end + end + + end +# end \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/ruby/swagger.mustache b/modules/swagger-codegen/src/main/resources/ruby/swagger.mustache new file mode 100644 index 00000000000..1cc3ea456c2 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/ruby/swagger.mustache @@ -0,0 +1,84 @@ +require 'monkey' +require 'swagger/configuration' +require 'swagger/request' +require 'swagger/response' +require 'swagger/version' +require 'logger' + +module Swagger + + class << self + attr_accessor :logger + + # A Swagger configuration object. Must act like a hash and return sensible + # values for all Swagger configuration options. See Swagger::Configuration. + attr_accessor :configuration + + attr_accessor :resources + + # Call this method to modify defaults in your initializers. + # + # @example + # Swagger.configure do |config| + # config.api_key = '1234567890abcdef' # required + # config.username = 'wordlover' # optional, but needed for user-related functions + # config.password = 'i<3words' # optional, but needed for user-related functions + # config.format = 'json' # optional, defaults to 'json' + # end + # + def configure + self.configuration ||= Configuration.new + yield(configuration) if block_given? + + # Configure logger. Default to use Rails + self.logger ||= configuration.logger || (defined?(Rails) ? Rails.logger : Logger.new(STDOUT)) + + # remove :// from scheme + configuration.scheme.sub!(/:\/\//, '') + + # remove http(s):// and anything after a slash + configuration.host.sub!(/https?:\/\//, '') + configuration.host = configuration.host.split('/').first + + # Add leading and trailing slashes to base_path + configuration.base_path = "/#{configuration.base_path}".gsub(/\/+/, '/') + configuration.base_path = "" if configuration.base_path == "/" + end + + def authenticated? + Swagger.configuration.auth_token.present? + end + + def de_authenticate + Swagger.configuration.auth_token = nil + end + + def authenticate + return if Swagger.authenticated? + + if Swagger.configuration.username.blank? || Swagger.configuration.password.blank? + raise ClientError, "Username and password are required to authenticate." + end + + request = Swagger::Request.new( + :get, + "account/authenticate/{username}", + :params => { + :username => Swagger.configuration.username, + :password => Swagger.configuration.password + } + ) + + response_body = request.response.body + Swagger.configuration.auth_token = response_body['token'] + end + + end + +end + +class ServerError < StandardError +end + +class ClientError < StandardError +end \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/ruby/swagger/configuration.mustache b/modules/swagger-codegen/src/main/resources/ruby/swagger/configuration.mustache new file mode 100644 index 00000000000..c0b3c46268c --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/ruby/swagger/configuration.mustache @@ -0,0 +1,22 @@ +module Swagger + + class Configuration + require 'swagger/version' + + attr_accessor :format, :api_key, :username, :password, :auth_token, :scheme, :host, :base_path, :user_agent, :logger, :inject_format, :force_ending_format, :camelize_params + + # Defaults go in here.. + def initialize + @format = 'json' + @scheme = 'http' + @host = 'api.wordnik.com' + @base_path = '/v4' + @user_agent = "ruby-#{Swagger::VERSION}" + @inject_format = true + @force_ending_format = false + @camelize_params = true + end + + end + +end \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/ruby/swagger/request.mustache b/modules/swagger-codegen/src/main/resources/ruby/swagger/request.mustache new file mode 100644 index 00000000000..7836cb0bf03 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/ruby/swagger/request.mustache @@ -0,0 +1,199 @@ +module Swagger + + class Request + require 'uri' + require 'addressable/uri' + require 'typhoeus' + require "swagger/version" + + attr_accessor :host, :path, :format, :params, :body, :http_method, :headers + + + # All requests must have an HTTP method and a path + # Optionals parameters are :params, :headers, :body, :format, :host + # + def initialize(http_method, path, attributes={}) + attributes[:format] ||= Swagger.configuration.format + attributes[:params] ||= {} + + # Set default headers + default_headers = { + 'Content-Type' => "application/#{attributes[:format].downcase}", + :api_key => Swagger.configuration.api_key + } + + # api_key from headers hash trumps the default, even if its value is blank + if attributes[:headers].present? && attributes[:headers].has_key?(:api_key) + default_headers.delete(:api_key) + end + + # api_key from params hash trumps all others (headers and default_headers) + if attributes[:params].present? && attributes[:params].has_key?(:api_key) + default_headers.delete(:api_key) + attributes[:headers].delete(:api_key) if attributes[:headers].present? + end + + # Merge argument headers into defaults + attributes[:headers] = default_headers.merge(attributes[:headers] || {}) + + # Stick in the auth token if there is one + if Swagger.authenticated? + attributes[:headers].merge!({:auth_token => Swagger.configuration.auth_token}) + end + + self.http_method = http_method.to_sym + self.path = path + attributes.each do |name, value| + send("#{name.to_s.underscore.to_sym}=", value) + end + end + + # Construct a base URL + # + def url(options = {}) + u = Addressable::URI.new( + :scheme => Swagger.configuration.scheme, + :host => Swagger.configuration.host, + :path => self.interpreted_path, + :query => self.query_string.sub(/\?/, '') + ).to_s + + # Drop trailing question mark, if present + u.sub! /\?$/, '' + + # Obfuscate API key? + u.sub! /api\_key=\w+/, 'api_key=YOUR_API_KEY' if options[:obfuscated] + + u + end + + # Iterate over the params hash, injecting any path values into the path string + # + # e.g. /word.{format}/{word}/entries => /word.json/cat/entries + def interpreted_path + p = self.path.dup + + # Fill in the path params + self.params.each_pair do |key, value| + p = p.gsub("{#{key}}", value.to_s) + end + + # Stick a .{format} placeholder into the path if there isn't + # one already or an actual format like json or xml + # e.g. /words/blah => /words.{format}/blah + if Swagger.configuration.inject_format + unless ['.json', '.xml', '{format}'].any? {|s| p.downcase.include? s } + p = p.sub(/^(\/?\w+)/, "\\1.#{format}") + end + end + + # Stick a .{format} placeholder on the end of the path if there isn't + # one already or an actual format like json or xml + # e.g. /words/blah => /words/blah.{format} + if Swagger.configuration.force_ending_format + unless ['.json', '.xml', '{format}'].any? {|s| p.downcase.include? s } + p = "#{p}.#{format}" + end + end + + p = p.sub("{format}", self.format.to_s) + + URI.encode [Swagger.configuration.base_path, p].join("/").gsub(/\/+/, '/') + end + + # Massage the request body into a state of readiness + # If body is a hash, camelize all keys then convert to a json string + # + def body=(value) + if value.is_a?(Hash) + value = value.inject({}) do |memo, (k,v)| + memo[k.to_s.camelize(:lower).to_sym] = v + memo + end + end + @body = value + end + + # If body is an object, JSONify it before making the actual request. + # + def outgoing_body + body.is_a?(String) ? body : body.to_json + end + + # Construct a query string from the query-string-type params + def query_string + + # Iterate over all params, + # .. removing the ones that are part of the path itself. + # .. stringifying values so Addressable doesn't blow up. + query_values = {} + self.params.each_pair do |key, value| + next if self.path.include? "{#{key}}" # skip path params + next if value.blank? && value.class != FalseClass # skip empties + if Swagger.configuration.camelize_params + key = key.to_s.camelize(:lower).to_sym unless key.to_sym == :api_key # api_key is not a camelCased param + end + query_values[key] = value.to_s + end + + # We don't want to end up with '?' as our query string + # if there aren't really any params + return "" if query_values.blank? + + # Addressable requires query_values to be set after initialization.. + qs = Addressable::URI.new + qs.query_values = query_values + qs.to_s + end + + def make + logger = Logger.new STDOUT + logger.debug self.url + response = case self.http_method.to_sym + when :get,:GET + Typhoeus::Request.get( + self.url, + :headers => self.headers.stringify_keys, + ) + + when :post,:POST + Typhoeus::Request.post( + self.url, + :body => self.outgoing_body, + :headers => self.headers.stringify_keys, + ) + + when :put,:PUT + Typhoeus::Request.put( + self.url, + :body => self.outgoing_body, + :headers => self.headers.stringify_keys, + ) + + when :delete,:DELETE + Typhoeus::Request.delete( + self.url, + :body => self.outgoing_body, + :headers => self.headers.stringify_keys, + ) + end + Response.new(response) + end + + def response + self.make + end + + def response_code_pretty + return unless @response.present? + @response.code.to_s + end + + def response_headers_pretty + return unless @response.present? + # JSON.pretty_generate(@response.headers).gsub(/\n/, '
') # <- This was for RestClient + @response.headers.gsub(/\n/, '
') # <- This is for Typhoeus + end + + end +end \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/ruby/swagger/response.mustache b/modules/swagger-codegen/src/main/resources/ruby/swagger/response.mustache new file mode 100644 index 00000000000..02a1a458eb4 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/ruby/swagger/response.mustache @@ -0,0 +1,70 @@ +module Swagger + + class Response + require 'json' + + attr_accessor :raw + + def initialize(raw) + self.raw = raw + + case self.code + when 500..510 then raise(ServerError, self.error_message) + when 299..426 then raise(ClientError, self.error_message) + end + end + + def code + raw.code + end + + # Account for error messages that take different forms... + def error_message + body['message'] + rescue + body + end + + # If body is JSON, parse it + # Otherwise return raw string + def body + JSON.parse raw.body + rescue + raw.body + end + + # `headers_hash` is a Typhoeus-specific extension of Hash, + # so simplify it back into a regular old Hash. + def headers + h = {} + raw.headers_hash.each {|k,v| h[k] = v } + h + end + + # Extract the response format from the header hash + # e.g. {'Content-Type' => 'application/json'} + def format + headers['Content-Type'].split("/").last.downcase + end + + def json? + format == 'json' + end + + def xml? + format == 'xml' + end + + def pretty_body + return unless body.present? + case format + when 'json' then JSON.pretty_generate(body).gsub(/\n/, '
') + end + end + + def pretty_headers + JSON.pretty_generate(headers).gsub(/\n/, '
') + end + + end +end \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/ruby/swagger/version.mustache b/modules/swagger-codegen/src/main/resources/ruby/swagger/version.mustache new file mode 100644 index 00000000000..39357c0ed6d --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/ruby/swagger/version.mustache @@ -0,0 +1,4 @@ +module Swagger + VERSION = "4.06.08" +end + diff --git a/modules/swagger-codegen/src/main/resources/scala/api.mustache b/modules/swagger-codegen/src/main/resources/scala/api.mustache new file mode 100644 index 00000000000..7c05406a5a8 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scala/api.mustache @@ -0,0 +1,68 @@ +package {{package}} + +{{#imports}}import {{import}} +{{/imports}} +import {{invokerPackage}}.ApiInvoker +import {{invokerPackage}}.ApiException + +import java.io.File +import java.util.Date + +import scala.collection.mutable.HashMap + +{{#operations}} +class {{classname}} { + var basePath: String = "{{basePath}}" + var apiInvoker = ApiInvoker + + def addHeader(key: String, value: String) = apiInvoker.defaultHeaders += key -> value + + {{#operation}} + def {{nickname}} ({{#allParams}}{{paramName}}: {{dataType}}{{#defaultValue}} = {{{defaultValue}}}{{/defaultValue}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) {{#returnType}}: Option[{{returnType}}]{{/returnType}} = { + // create path and map variables + val path = "{{path}}".replaceAll("\\{format\\}","json"){{#pathParams}}.replaceAll("\\{" + "{{baseName}}" + "\\}",apiInvoker.escape({{paramName}})) + + {{/pathParams}} + + {{newline}} + val contentType = { + {{#bodyParam}}if({{paramName}} != null && {{paramName}}.isInstanceOf[File] ) + "multipart/form-data" + else "application/json" + {{/bodyParam}} + {{^bodyParam}}"application/json"{{/bodyParam}} + } + + // query params + val queryParams = new HashMap[String, String] + val headerParams = new HashMap[String, String] + + {{#requiredParamCount}} + // verify required params are set + (List({{/requiredParamCount}}{{#requiredParams}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/requiredParams}}{{#requiredParamCount}}).filter(_ != null)).size match { + case {{requiredParamCount}} => // all required values set + case _ => throw new Exception("missing required params") + } + {{/requiredParamCount}} + + {{#queryParams}}if(String.valueOf({{paramName}}) != "null") queryParams += "{{baseName}}" -> {{paramName}}.toString + {{/queryParams}} + + {{#headerParams}}headerParams += "{{baseName}}" -> {{paramName}} + {{/headerParams}} + + try { + apiInvoker.invokeApi(basePath, path, "{{httpMethod}}", queryParams.toMap, {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}None{{/bodyParam}}, headerParams.toMap, contentType) match { + case s: String => + {{#returnType}} Some(ApiInvoker.deserialize(s, "{{returnContainer}}", classOf[{{returnBaseType}}]).asInstanceOf[{{returnType}}]) + {{/returnType}} + case _ => None + } + } catch { + case ex: ApiException if ex.code == 404 => None + case ex: ApiException => throw ex + } + } + {{/operation}} +} +{{/operations}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/scala/apiInvoker.mustache b/modules/swagger-codegen/src/main/resources/scala/apiInvoker.mustache new file mode 100644 index 00000000000..5c6d60d37b5 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scala/apiInvoker.mustache @@ -0,0 +1,164 @@ +package {{invokerPackage}} + +import com.sun.jersey.api.client.Client +import com.sun.jersey.api.client.ClientResponse +import com.sun.jersey.api.client.config.ClientConfig +import com.sun.jersey.api.client.config.DefaultClientConfig +import com.sun.jersey.api.client.filter.LoggingFilter + +import com.sun.jersey.multipart.FormDataMultiPart +import com.sun.jersey.multipart.file.FileDataBodyPart + +import java.io.File +import java.net.URLEncoder +import javax.ws.rs.core.MediaType + +import scala.collection.JavaConverters._ +import scala.collection.mutable.HashMap + +import com.fasterxml.jackson.module.scala.DefaultScalaModule +import com.fasterxml.jackson.core.JsonGenerator.Feature +import com.fasterxml.jackson.databind._ +import com.fasterxml.jackson.annotation._ +import com.fasterxml.jackson.databind.annotation.JsonSerialize + +object ScalaJsonUtil { + def getJsonMapper = { + val mapper = new ObjectMapper() + mapper.registerModule(new DefaultScalaModule()) + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT) + mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY) + mapper + } +} + +object ApiInvoker { + val mapper = ScalaJsonUtil.getJsonMapper + val defaultHeaders: HashMap[String, String] = HashMap() + val hostMap: HashMap[String, Client] = HashMap() + + def escape(value: String): String = { + URLEncoder.encode(value, "utf-8").replaceAll("\\+", "%20") + } + + def escape(value: Long): String = value.toString + def escape(value: Double): String = value.toString + def escape(value: Float): String = value.toString + + def deserialize(json: String, containerType: String, cls: Class[_]) = { + if (cls == classOf[String]) { + json match { + case s: String => { + if (s.startsWith("\"") && s.endsWith("\"") && s.length > 1) s.substring(1, s.length - 2) + else s + } + case _ => null + } + } else { + containerType.toLowerCase match { + case "array" => { + val typeInfo = mapper.getTypeFactory().constructCollectionType(classOf[java.util.List[_]], cls) + val response = mapper.readValue(json, typeInfo).asInstanceOf[java.util.List[_]] + response.asScala.toList + } + case "list" => { + val typeInfo = mapper.getTypeFactory().constructCollectionType(classOf[java.util.List[_]], cls) + val response = mapper.readValue(json, typeInfo).asInstanceOf[java.util.List[_]] + response.asScala.toList + } + case _ => { + json match { + case e: String if ("\"\"" == e) => null + case _ => mapper.readValue(json, cls) + } + } + } + } + } + + def serialize(obj: AnyRef): String = { + if (obj != null) { + obj match { + case e: List[_] => mapper.writeValueAsString(obj.asInstanceOf[List[_]].asJava) + case _ => mapper.writeValueAsString(obj) + } + } else null + } + + def invokeApi(host: String, path: String, method: String, queryParams: Map[String, String], body: AnyRef, headerParams: Map[String, String], contentType: String): String = { + val client = getClient(host) + + val querystring = queryParams.filter(k => k._2 != null).map(k => (escape(k._1) + "=" + escape(k._2))).mkString("?", "&", "") + val builder = client.resource(host + path + querystring).accept(contentType) + headerParams.map(p => builder.header(p._1, p._2)) + defaultHeaders.map(p => { + headerParams.contains(p._1) match { + case true => // override default with supplied header + case false => if (p._2 != null) builder.header(p._1, p._2) + } + }) + + val response: ClientResponse = method match { + case "GET" => { + builder.get(classOf[ClientResponse]).asInstanceOf[ClientResponse] + } + case "POST" => { + if(body != null && body.isInstanceOf[File]) { + val file = body.asInstanceOf[File] + val form = new FormDataMultiPart() + form.field("filename", file.getName()) + form.bodyPart(new FileDataBodyPart("file", file, MediaType.MULTIPART_FORM_DATA_TYPE)) + builder.post(classOf[ClientResponse], form) + } + else { + if(body == null) builder.post(classOf[ClientResponse], serialize(body)) + else builder.`type`(contentType).post(classOf[ClientResponse], serialize(body)) + } + } + case "PUT" => { + if(body == null) builder.put(classOf[ClientResponse], null) + else builder.`type`(contentType).put(classOf[ClientResponse], serialize(body)) + } + case "DELETE" => { + builder.delete(classOf[ClientResponse]) + } + case _ => null + } + response.getClientResponseStatus().getStatusCode() match { + case 204 => "" + case code: Int if (Range(200, 299).contains(code)) => { + response.hasEntity() match { + case true => response.getEntity(classOf[String]) + case false => "" + } + } + case _ => { + val entity = response.hasEntity() match { + case true => response.getEntity(classOf[String]) + case false => "no data" + } + throw new ApiException( + response.getClientResponseStatus().getStatusCode(), + entity) + } + } + } + + def getClient(host: String): Client = { + hostMap.contains(host) match { + case true => hostMap(host) + case false => { + val client = Client.create() + // client.addFilter(new LoggingFilter()) + hostMap += host -> client + client + } + } + } +} + +class ApiException(val code: Int, msg: String) extends RuntimeException(msg) + diff --git a/modules/swagger-codegen/src/main/resources/scala/model.mustache b/modules/swagger-codegen/src/main/resources/scala/model.mustache new file mode 100644 index 00000000000..a45b71a8f8e --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scala/model.mustache @@ -0,0 +1,15 @@ +package {{package}} + +{{#imports}}import {{import}} +{{/imports}} + +{{#models}} + +{{#model}} + +case class {{classname}} ( + {{#vars}}{{#description}}/* {{{description}}} */ + {{/description}}{{name}}: {{{datatype}}}{{#hasMore}},{{/hasMore}}{{^hasMore}}){{/hasMore}} + {{/vars}} +{{/model}} +{{/models}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/scala/pom.mustache b/modules/swagger-codegen/src/main/resources/scala/pom.mustache new file mode 100644 index 00000000000..ac6a81caa46 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scala/pom.mustache @@ -0,0 +1,232 @@ + + 4.0.0 + {{groupId}} + {{artifactId}} + jar + {{artifactId}} + {{artifactVersion}} + + 2.2.0 + + + + + maven-mongodb-plugin-repo + maven mongodb plugin repository + http://maven-mongodb-plugin.googlecode.com/svn/maven/repo + default + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12 + + + + loggerPath + conf/log4j.properties + + + -Xms512m -Xmx1500m + methods + pertest + + + + maven-dependency-plugin + + + package + + copy-dependencies + + + ${project.build.directory}/lib + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.2 + + + + jar + test-jar + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add_sources + generate-sources + + add-source + + + + src/main/java + + + + + add_test_sources + generate-test-sources + + add-test-source + + + + src/test/java + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.6 + 1.6 + + + + net.alchim31.maven + scala-maven-plugin + ${scala-maven-plugin-version} + + + scala-compile-first + process-resources + + add-source + compile + + + + scala-test-compile + process-test-resources + + testCompile + + + + + + -Xms128m + -Xmx1500m + + + + + + + + + org.scala-tools + maven-scala-plugin + + ${scala-version} + + + + + + + com.sun.jersey + jersey-client + ${jersey-version} + compile + + + com.sun.jersey.contribs + jersey-multipart + ${jersey-version} + compile + + + org.scala-lang + scala-library + ${scala-version} + compile + + + com.wordnik + swagger-core_${scala-short-version} + ${swagger-core-version} + compile + + + org.scalatest + scalatest_${scala-short-version} + ${scala-test-version} + test + + + junit + junit + ${junit-version} + test + + + joda-time + joda-time + ${joda-time-version} + + + org.joda + joda-convert + ${joda-version} + + + + + scala_2.10 + + 2.10.3 + 2.10 + 1.3.2 + 2.1.2 + + + + scala_2.9.1 + + true + + + 2.9.1-1 + 2.9.1 + 1.1.0 + 1.6.1 + + + + + 1.2 + 2.2 + 1.7 + 4.8.1 + 1.0.0 + 4.8.1 + 3.1.5 + + diff --git a/modules/swagger-codegen/src/main/resources/scalatra/Bootstrap.mustache b/modules/swagger-codegen/src/main/resources/scalatra/Bootstrap.mustache new file mode 100644 index 00000000000..64c0b07eb28 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalatra/Bootstrap.mustache @@ -0,0 +1,20 @@ +import {{apiPackage}}._ +import akka.actor.ActorSystem +import com.wordnik.swagger.app.{ResourcesApp, SwaggerApp} +import javax.servlet.ServletContext +import org.scalatra.LifeCycle + +class ScalatraBootstrap extends LifeCycle { + implicit val swagger = new SwaggerApp + + override def init(context: ServletContext) { + implicit val system = ActorSystem("appActorSystem") + try { + {{#apiInfo}}{{#apis}}context mount (new {{classname}}, "/{{baseName}}/*") + {{/apis}}{{/apiInfo}} + context mount (new ResourcesApp, "/api-docs/*") + } catch { + case e: Throwable => e.printStackTrace() + } + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/scalatra/JettyMain.scala b/modules/swagger-codegen/src/main/resources/scalatra/JettyMain.scala new file mode 100644 index 00000000000..e25f16ba392 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalatra/JettyMain.scala @@ -0,0 +1,43 @@ +import org.eclipse.jetty.server._ +import org.eclipse.jetty.webapp.WebAppContext +import org.scalatra.servlet.ScalatraListener + +object JettyMain { + + object conf { + val port = sys.env.get("PORT") map (_.toInt) getOrElse (8080) + val stopTimeout = sys.env.get("STOP_TIMEOUT") map (_.toInt) getOrElse (5000) + val connectorIdleTimeout = sys.env.get("CONNECTOR_IDLE_TIMEOUT") map (_.toInt) getOrElse (90000) + val webapp = sys.env.get("PUBLIC") getOrElse "webapp" + val contextPath = sys.env.get("CONTEXT_PATH") getOrElse "/" + } + + def main(args: Array[String]) = { + val server: Server = new Server + println("starting jetty") + + server setStopTimeout conf.stopTimeout + //server setDumpAfterStart true + server setStopAtShutdown true + + val httpConfig = new HttpConfiguration() + httpConfig setSendDateHeader true + httpConfig setSendServerVersion false + + val connector = new NetworkTrafficServerConnector(server, new HttpConnectionFactory(httpConfig)) + connector setPort conf.port + connector setSoLingerTime 0 + connector setIdleTimeout conf.connectorIdleTimeout + server addConnector connector + + val webapp = conf.webapp + val webApp = new WebAppContext + webApp setContextPath conf.contextPath + webApp setResourceBase conf.webapp + webApp setEventListeners Array(new ScalatraListener) + + server setHandler webApp + + server.start() + } +} diff --git a/modules/swagger-codegen/src/main/resources/scalatra/JsonUtil.scala b/modules/swagger-codegen/src/main/resources/scalatra/JsonUtil.scala new file mode 100644 index 00000000000..691a82f563b --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalatra/JsonUtil.scala @@ -0,0 +1,12 @@ +package json + +import com.fasterxml.jackson.module.scala.DefaultScalaModule +import com.fasterxml.jackson.core.JsonGenerator.Feature +import com.fasterxml.jackson.databind._ + +object JsonUtil { + val mapper = new ObjectMapper() + mapper.registerModule(new DefaultScalaModule()) + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/scalatra/README.mustache b/modules/swagger-codegen/src/main/resources/scalatra/README.mustache new file mode 100644 index 00000000000..f8a560b776f --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalatra/README.mustache @@ -0,0 +1,10 @@ +# Swagger generated server + +## Overview +This server was generated by the [swagger-codegen](https://github.com/wordnik/swagger-codegen) project. By using the +[swagger-spec](https://github.com/wordnik/swagger-core/wiki) from a remote server, you can easily generate a server stub. This +is an example of building a swagger-enabled scalatra server. + +This example uses the [scalatra](http://scalatra.org/) framework. To see how to make this your own, look here: + +[README](https://github.com/wordnik/swagger-codegen/tree/master/samples/server-generator/scalatra) \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/scalatra/ServletApp.mustache b/modules/swagger-codegen/src/main/resources/scalatra/ServletApp.mustache new file mode 100644 index 00000000000..f6e53468ec9 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalatra/ServletApp.mustache @@ -0,0 +1,39 @@ +package com.wordnik.swagger.app + +import _root_.akka.actor.ActorSystem + +import org.scalatra.swagger.{ ApiInfo, SwaggerWithAuth, Swagger } +import org.scalatra.swagger.{JacksonSwaggerBase, Swagger} +import org.scalatra.ScalatraServlet +import org.json4s.{DefaultFormats, Formats} + +class ResourcesApp(implicit protected val system: ActorSystem, val swagger: SwaggerApp) + extends ScalatraServlet with JacksonSwaggerBase { + before() { + response.headers += ("Access-Control-Allow-Origin" -> "*") + } + + protected def buildFullUrl(path: String) = if (path.startsWith("http")) path else { + val port = request.getServerPort + val h = request.getServerName + val prot = if (port == 443) "https" else "http" + val (proto, host) = if (port != 80 && port != 443) ("http", h+":"+port.toString) else (prot, h) + "%s://%s%s%s".format( + proto, + host, + request.getContextPath, + path) + } +} + +class SwaggerApp extends Swagger(apiInfo = ApiSwagger.apiInfo, apiVersion = "1.0", swaggerVersion = "1.2") + +object ApiSwagger { + val apiInfo = ApiInfo( + """{{{appName}}}""", + """{{{appDescription}}}""", + """{{{infoUrl}}}""", + """{{{infoEmail}}}""", + """{{{licenseInfo}}}""", + """{{{licenseUrl}}}""") +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/scalatra/api.mustache b/modules/swagger-codegen/src/main/resources/scalatra/api.mustache new file mode 100644 index 00000000000..54710361fe9 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalatra/api.mustache @@ -0,0 +1,94 @@ +package {{package}} + +{{#imports}}import {{import}} +{{/imports}} + +import java.io.File + +import org.scalatra.{ TypedParamSupport, ScalatraServlet } +import org.scalatra.swagger._ +import org.json4s._ +import org.json4s.JsonDSL._ +import org.scalatra.json.{ JValueResult, JacksonJsonSupport } +import org.scalatra.servlet.{FileUploadSupport, MultipartConfig, SizeConstraintExceededException} + +import scala.collection.JavaConverters._ + +class {{classname}} (implicit val swagger: Swagger) extends ScalatraServlet + with FileUploadSupport + with JacksonJsonSupport + with SwaggerSupport { + protected implicit val jsonFormats: Formats = DefaultFormats + + protected val applicationDescription: String = "{{classname}}" + override protected val applicationName: Option[String] = Some("{{baseName}}") + + before() { + contentType = formats("json") + response.headers += ("Access-Control-Allow-Origin" -> "*") + } +{{#operations}} +{{#operation}} + {{newline}} + + val {{nickname}}Operation = (apiOperation[{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Unit{{/returnType}}]("{{nickname}}") + summary "{{{summary}}}" + parameters( + {{#allParams}}{{#isQueryParam}}queryParam[{{dataType}}]("{{paramName}}").description(""){{^required}}.optional{{/required}}{{#defaultValue}}.defaultValue({{{defaultValue}}}){{/defaultValue}} + {{/isQueryParam}} + {{#isPathParam}}pathParam[{{dataType}}]("{{paramName}}").description(""){{#defaultValue}}.defaultValue({{{defaultValue}}}){{/defaultValue}} + {{/isPathParam}} + {{#isHeaderParam}}headerParam[{{dataType}}]("{{paramName}}").description(""){{^required}}.optional{{/required}}{{#defaultValue}}.defaultValue({{{defaultValue}}}){{/defaultValue}} + {{/isHeaderParam}} + {{#isBodyParam}}bodyParam[{{dataType}}]("{{paramName}}").description(""){{^required}}.optional{{/required}}{{#defaultValue}}.defaultValue({{{defaultValue}}}){{/defaultValue}} + {{/isBodyParam}} + {{#isFormParam}}formParam[{{dataType}}]("{{paramName}}").description(""){{^required}}.optional{{/required}}{{#defaultValue}}.defaultValue({{{defaultValue}}}){{/defaultValue}} + {{/isFormParam}} + {{#hasMore}},{{/hasMore}} + {{/allParams}}) + ) + + {{httpMethod}}("{{path}}",operation({{nickname}}Operation)) { + {{#allParams}} + {{#isFile}} + val {{paramName}} = fileParams("{{paramName}}") + {{/isFile}} + {{^isFile}} + {{#isPathParam}} + val {{paramName}} = params.getOrElse("{{paramName}}", halt(400)) + {{/isPathParam}} + + {{#isQueryParam}} + {{#collectionFormat}}val {{paramName}}String = params.getAs[String]("{{paramName}}") + val {{paramName}} = if("{{collectionFormat}}".equals("default")) { + {{paramName}}String match { + case Some(str) => str.split(",") + case None => List() + } + } + else + List() + {{/collectionFormat}} + {{^collectionFormat}}val {{paramName}} = params.getAs[{{dataType}}]("{{paramName}}"){{/collectionFormat}} + + {{/isQueryParam}} + + {{#isHeaderParam}} + val {{paramName}} = request.getHeader("{{paramName}}") + {{/isHeaderParam}} + + {{#isFormParam}} + val {{paramName}} = params.getAs[{{dataType}}]("{{paramName}}") + {{/isFormParam}} + + {{#isBodyParam}} + val {{paramName}} = parsedBody.extract[{{dataType}}] + {{/isBodyParam}} + {{/isFile}} + println("{{paramName}}: " + {{paramName}}) + {{/allParams}} + } + +{{/operation}} +{{/operations}} +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/scalatra/build.sbt b/modules/swagger-codegen/src/main/resources/scalatra/build.sbt new file mode 100644 index 00000000000..afe84c2c7f0 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalatra/build.sbt @@ -0,0 +1,64 @@ +import AssemblyKeys._ // put this at the top of the file + +import NativePackagerKeys._ + +packageArchetype.java_server + +assemblySettings + +scalariformSettings + +organization := "com.wordnik" + +seq(webSettings :_*) + +mainClass in assembly := Some("JettyMain") + +name := "scalatra-sample" + +version := "0.1.0-SNAPSHOT" + +scalaVersion := "2.11.2" + +scalacOptions += "-language:postfixOps" + +libraryDependencies ++= Seq( + "org.scalatest" %% "scalatest" % "2.2.1" % "test", + "org.scalatra" %% "scalatra" % "2.3.0.RC3", + "org.scalatra" %% "scalatra-scalate" % "2.3.0.RC3", + "org.scalatra" %% "scalatra-json" % "2.3.0.RC3", + "org.scalatra" %% "scalatra-swagger" % "2.3.0.RC3", + "org.scalatra" %% "scalatra-swagger-ext" % "2.3.0.RC3", + "org.scalatra" %% "scalatra-slf4j" % "2.3.0.RC3", + "org.json4s" %% "json4s-jackson" % "3.2.10", + "org.json4s" %% "json4s-ext" % "3.2.10", + "commons-codec" % "commons-codec" % "1.7", + "net.databinder.dispatch" %% "dispatch-core" % "0.11.2", + //"net.databinder.dispatch" %% "json4s-jackson" % "0.11.2", + "net.databinder.dispatch" %% "dispatch-json4s-jackson" % "0.11.2", + "com.typesafe.akka" %% "akka-actor" % "2.3.6", + "org.eclipse.jetty" % "jetty-server" % "9.2.3.v20140905" % "container;compile;test", + "org.eclipse.jetty" % "jetty-webapp" % "9.2.3.v20140905" % "container;compile;test", + "org.eclipse.jetty.orbit" % "javax.servlet" % "3.0.0.v201112011016" % "container;compile;provided;test" artifacts (Artifact("javax.servlet", "jar", "jar")) +) + +resolvers += "Local Maven Repository" at "file://"+Path.userHome.absolutePath+"/.m2/repository" + +resolvers += "Sonatype OSS Snapshots" at "http://oss.sonatype.org/content/repositories/snapshots/" + +resolvers += "Sonatype OSS Releases" at "http://oss.sonatype.org/content/repositories/releases/" + +ivyXML := + + + + + +mergeStrategy in assembly <<= (mergeStrategy in assembly) { + (old) => { + case "about.html" => MergeStrategy.discard + case x => old(x) + } +} + +net.virtualvoid.sbt.graph.Plugin.graphSettings diff --git a/modules/swagger-codegen/src/main/resources/scalatra/model.mustache b/modules/swagger-codegen/src/main/resources/scalatra/model.mustache new file mode 100644 index 00000000000..8c5d1954662 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalatra/model.mustache @@ -0,0 +1,15 @@ +package {{package}} + +{{#imports}}import {{import}} +{{/imports}} + +{{#models}} + +{{#model}} +case class {{classname}} ( + {{#vars}}{{name}}: {{#isNotRequired}}Option[{{/isNotRequired}}{{datatype}}{{#isNotRequired}}] {{#description}} // {{description}}{{/description}} + {{/isNotRequired}}{{#hasMore}}, + {{/hasMore}}{{/vars}} +) +{{/model}} +{{/models}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/scalatra/project/build.properties b/modules/swagger-codegen/src/main/resources/scalatra/project/build.properties new file mode 100644 index 00000000000..be6c454fbac --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalatra/project/build.properties @@ -0,0 +1 @@ +sbt.version=0.13.5 diff --git a/modules/swagger-codegen/src/main/resources/scalatra/project/plugins.sbt b/modules/swagger-codegen/src/main/resources/scalatra/project/plugins.sbt new file mode 100644 index 00000000000..7358abbbbc6 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalatra/project/plugins.sbt @@ -0,0 +1,9 @@ +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.10.1") + +addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "0.7.5") + +addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "0.9.0") + +addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.3.0") + +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.4") diff --git a/modules/swagger-codegen/src/main/resources/scalatra/sbt b/modules/swagger-codegen/src/main/resources/scalatra/sbt new file mode 100755 index 00000000000..08e58821219 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/scalatra/sbt @@ -0,0 +1,525 @@ +#!/usr/bin/env bash +# +# A more capable sbt runner, coincidentally also called sbt. +# Author: Paul Phillips + +# todo - make this dynamic +declare -r sbt_release_version="0.13.6" +declare -r sbt_unreleased_version="0.13.6" +declare -r buildProps="project/build.properties" + +declare sbt_jar sbt_dir sbt_create sbt_version +declare scala_version sbt_explicit_version +declare verbose noshare batch trace_level log_level +declare sbt_saved_stty debugUs + +echoerr () { echo >&2 "$@"; } +vlog () { [[ -n "$verbose" ]] && echoerr "$@"; } + +# spaces are possible, e.g. sbt.version = 0.13.0 +build_props_sbt () { + [[ -r "$buildProps" ]] && \ + grep '^sbt\.version' "$buildProps" | tr '=' ' ' | awk '{ print $2; }' +} + +update_build_props_sbt () { + local ver="$1" + local old="$(build_props_sbt)" + + [[ -r "$buildProps" ]] && [[ "$ver" != "$old" ]] && { + perl -pi -e "s/^sbt\.version\b.*\$/sbt.version=${ver}/" "$buildProps" + grep -q '^sbt.version[ =]' "$buildProps" || printf "\nsbt.version=%s\n" "$ver" >> "$buildProps" + + vlog "!!!" + vlog "!!! Updated file $buildProps setting sbt.version to: $ver" + vlog "!!! Previous value was: $old" + vlog "!!!" + } +} + +set_sbt_version () { + sbt_version="${sbt_explicit_version:-$(build_props_sbt)}" + [[ -n "$sbt_version" ]] || sbt_version=$sbt_release_version + export sbt_version +} + +# restore stty settings (echo in particular) +onSbtRunnerExit() { + [[ -n "$sbt_saved_stty" ]] || return + vlog "" + vlog "restoring stty: $sbt_saved_stty" + stty "$sbt_saved_stty" + unset sbt_saved_stty +} + +# save stty and trap exit, to ensure echo is reenabled if we are interrupted. +trap onSbtRunnerExit EXIT +sbt_saved_stty="$(stty -g 2>/dev/null)" +vlog "Saved stty: $sbt_saved_stty" + +# this seems to cover the bases on OSX, and someone will +# have to tell me about the others. +get_script_path () { + local path="$1" + [[ -L "$path" ]] || { echo "$path" ; return; } + + local target="$(readlink "$path")" + if [[ "${target:0:1}" == "/" ]]; then + echo "$target" + else + echo "${path%/*}/$target" + fi +} + +die() { + echo "Aborting: $@" + exit 1 +} + +make_url () { + version="$1" + + case "$version" in + 0.7.*) echo "http://simple-build-tool.googlecode.com/files/sbt-launch-0.7.7.jar" ;; + 0.10.* ) echo "$sbt_launch_repo/org.scala-tools.sbt/sbt-launch/$version/sbt-launch.jar" ;; + 0.11.[12]) echo "$sbt_launch_repo/org.scala-tools.sbt/sbt-launch/$version/sbt-launch.jar" ;; + *) echo "$sbt_launch_repo/org.scala-sbt/sbt-launch/$version/sbt-launch.jar" ;; + esac +} + +init_default_option_file () { + local overriding_var="${!1}" + local default_file="$2" + if [[ ! -r "$default_file" && "$overriding_var" =~ ^@(.*)$ ]]; then + local envvar_file="${BASH_REMATCH[1]}" + if [[ -r "$envvar_file" ]]; then + default_file="$envvar_file" + fi + fi + echo "$default_file" +} + +declare -r cms_opts="-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC" +declare -r jit_opts="-XX:ReservedCodeCacheSize=256m -XX:+TieredCompilation" +declare -r default_jvm_opts_common="-Xms512m -Xmx1536m -Xss2m $jit_opts $cms_opts" +declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy" +declare -r latest_28="2.8.2" +declare -r latest_29="2.9.3" +declare -r latest_210="2.10.4" +declare -r latest_211="2.11.2" + +declare -r script_path="$(get_script_path "$BASH_SOURCE")" +declare -r script_name="${script_path##*/}" + +# some non-read-onlies set with defaults +declare java_cmd="java" +declare sbt_opts_file="$(init_default_option_file SBT_OPTS .sbtopts)" +declare jvm_opts_file="$(init_default_option_file JVM_OPTS .jvmopts)" +declare sbt_launch_repo="http://typesafe.artifactoryonline.com/typesafe/ivy-releases" + +# pull -J and -D options to give to java. +declare -a residual_args +declare -a java_args +declare -a scalac_args +declare -a sbt_commands + +# args to jvm/sbt via files or environment variables +declare -a extra_jvm_opts extra_sbt_opts + +# if set, use JAVA_HOME over java found in path +[[ -e "$JAVA_HOME/bin/java" ]] && java_cmd="$JAVA_HOME/bin/java" + +# directory to store sbt launchers +declare sbt_launch_dir="$HOME/.sbt/launchers" +[[ -d "$sbt_launch_dir" ]] || mkdir -p "$sbt_launch_dir" +[[ -w "$sbt_launch_dir" ]] || sbt_launch_dir="$(mktemp -d -t sbt_extras_launchers.XXXXXX)" + +java_version () { + local version=$("$java_cmd" -version 2>&1 | grep -e 'java version' | awk '{ print $3 }' | tr -d \") + vlog "Detected Java version: $version" + echo "${version:2:1}" +} + +# MaxPermSize critical on pre-8 jvms but incurs noisy warning on 8+ +default_jvm_opts () { + local v="$(java_version)" + if [[ $v -ge 8 ]]; then + echo "$default_jvm_opts_common" + else + echo "-XX:MaxPermSize=384m $default_jvm_opts_common" + fi +} + +build_props_scala () { + if [[ -r "$buildProps" ]]; then + versionLine="$(grep '^build.scala.versions' "$buildProps")" + versionString="${versionLine##build.scala.versions=}" + echo "${versionString%% .*}" + fi +} + +execRunner () { + # print the arguments one to a line, quoting any containing spaces + vlog "# Executing command line:" && { + for arg; do + if [[ -n "$arg" ]]; then + if printf "%s\n" "$arg" | grep -q ' '; then + printf >&2 "\"%s\"\n" "$arg" + else + printf >&2 "%s\n" "$arg" + fi + fi + done + vlog "" + } + + [[ -n "$batch" ]] && exec /dev/null; then + curl --fail --silent "$url" --output "$jar" + elif which wget >/dev/null; then + wget --quiet -O "$jar" "$url" + fi + } && [[ -r "$jar" ]] +} + +acquire_sbt_jar () { + sbt_url="$(jar_url "$sbt_version")" + sbt_jar="$(jar_file "$sbt_version")" + + [[ -r "$sbt_jar" ]] || download_url "$sbt_url" "$sbt_jar" +} + +usage () { + cat < display stack traces with a max of frames (default: -1, traces suppressed) + -debug-inc enable debugging log for the incremental compiler + -no-colors disable ANSI color codes + -sbt-create start sbt even if current directory contains no sbt project + -sbt-dir path to global settings/plugins directory (default: ~/.sbt/) + -sbt-boot path to shared boot directory (default: ~/.sbt/boot in 0.11+) + -ivy path to local Ivy repository (default: ~/.ivy2) + -no-share use all local caches; no sharing + -offline put sbt in offline mode + -jvm-debug Turn on JVM debugging, open at the given port. + -batch Disable interactive mode + -prompt Set the sbt prompt; in expr, 's' is the State and 'e' is Extracted + + # sbt version (default: sbt.version from $buildProps if present, otherwise $sbt_release_version) + -sbt-force-latest force the use of the latest release of sbt: $sbt_release_version + -sbt-version use the specified version of sbt (default: $sbt_release_version) + -sbt-dev use the latest pre-release version of sbt: $sbt_unreleased_version + -sbt-jar use the specified jar as the sbt launcher + -sbt-launch-dir directory to hold sbt launchers (default: ~/.sbt/launchers) + -sbt-launch-repo repo url for downloading sbt launcher jar (default: $sbt_launch_repo) + + # scala version (default: as chosen by sbt) + -28 use $latest_28 + -29 use $latest_29 + -210 use $latest_210 + -211 use $latest_211 + -scala-home use the scala build at the specified directory + -scala-version use the specified version of scala + -binary-version use the specified scala version when searching for dependencies + + # java version (default: java from PATH, currently $(java -version 2>&1 | grep version)) + -java-home alternate JAVA_HOME + + # passing options to the jvm - note it does NOT use JAVA_OPTS due to pollution + # The default set is used if JVM_OPTS is unset and no -jvm-opts file is found + $(default_jvm_opts) + JVM_OPTS environment variable holding either the jvm args directly, or + the reference to a file containing jvm args if given path is prepended by '@' (e.g. '@/etc/jvmopts') + Note: "@"-file is overridden by local '.jvmopts' or '-jvm-opts' argument. + -jvm-opts file containing jvm args (if not given, .jvmopts in project root is used if present) + -Dkey=val pass -Dkey=val directly to the jvm + -J-X pass option -X directly to the jvm (-J is stripped) + + # passing options to sbt, OR to this runner + SBT_OPTS environment variable holding either the sbt args directly, or + the reference to a file containing sbt args if given path is prepended by '@' (e.g. '@/etc/sbtopts') + Note: "@"-file is overridden by local '.sbtopts' or '-sbt-opts' argument. + -sbt-opts file containing sbt args (if not given, .sbtopts in project root is used if present) + -S-X add -X to sbt's scalacOptions (-S is stripped) +EOM +} + +addJava () { + vlog "[addJava] arg = '$1'" + java_args=( "${java_args[@]}" "$1" ) +} +addSbt () { + vlog "[addSbt] arg = '$1'" + sbt_commands=( "${sbt_commands[@]}" "$1" ) +} +setThisBuild () { + vlog "[addBuild] args = '$@'" + local key="$1" && shift + addSbt "set $key in ThisBuild := $@" +} + +addScalac () { + vlog "[addScalac] arg = '$1'" + scalac_args=( "${scalac_args[@]}" "$1" ) +} +addResidual () { + vlog "[residual] arg = '$1'" + residual_args=( "${residual_args[@]}" "$1" ) +} +addResolver () { + addSbt "set resolvers += $1" +} +addDebugger () { + addJava "-Xdebug" + addJava "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=$1" +} +setScalaVersion () { + [[ "$1" == *"-SNAPSHOT" ]] && addResolver 'Resolver.sonatypeRepo("snapshots")' + addSbt "++ $1" +} + +process_args () +{ + require_arg () { + local type="$1" + local opt="$2" + local arg="$3" + + if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then + die "$opt requires <$type> argument" + fi + } + while [[ $# -gt 0 ]]; do + case "$1" in + -h|-help) usage; exit 1 ;; + -v) verbose=true && shift ;; + -d) addSbt "--debug" && shift ;; + -w) addSbt "--warn" && shift ;; + -q) addSbt "--error" && shift ;; + -x) debugUs=true && shift ;; + -trace) require_arg integer "$1" "$2" && trace_level="$2" && shift 2 ;; + -ivy) require_arg path "$1" "$2" && addJava "-Dsbt.ivy.home=$2" && shift 2 ;; + -no-colors) addJava "-Dsbt.log.noformat=true" && shift ;; + -no-share) noshare=true && shift ;; + -sbt-boot) require_arg path "$1" "$2" && addJava "-Dsbt.boot.directory=$2" && shift 2 ;; + -sbt-dir) require_arg path "$1" "$2" && sbt_dir="$2" && shift 2 ;; + -debug-inc) addJava "-Dxsbt.inc.debug=true" && shift ;; + -offline) addSbt "set offline := true" && shift ;; + -jvm-debug) require_arg port "$1" "$2" && addDebugger "$2" && shift 2 ;; + -batch) batch=true && shift ;; + -prompt) require_arg "expr" "$1" "$2" && setThisBuild shellPrompt "(s => { val e = Project.extract(s) ; $2 })" && shift 2 ;; + + -sbt-create) sbt_create=true && shift ;; + -sbt-jar) require_arg path "$1" "$2" && sbt_jar="$2" && shift 2 ;; + -sbt-version) require_arg version "$1" "$2" && sbt_explicit_version="$2" && shift 2 ;; + -sbt-force-latest) sbt_explicit_version="$sbt_release_version" && shift ;; + -sbt-dev) sbt_explicit_version="$sbt_unreleased_version" && shift ;; + -sbt-launch-dir) require_arg path "$1" "$2" && sbt_launch_dir="$2" && shift 2 ;; + -sbt-launch-repo) require_arg path "$1" "$2" && sbt_launch_repo="$2" && shift 2 ;; + -scala-version) require_arg version "$1" "$2" && setScalaVersion "$2" && shift 2 ;; + -binary-version) require_arg version "$1" "$2" && setThisBuild scalaBinaryVersion "\"$2\"" && shift 2 ;; + -scala-home) require_arg path "$1" "$2" && setThisBuild scalaHome "Some(file(\"$2\"))" && shift 2 ;; + -java-home) require_arg path "$1" "$2" && java_cmd="$2/bin/java" && shift 2 ;; + -sbt-opts) require_arg path "$1" "$2" && sbt_opts_file="$2" && shift 2 ;; + -jvm-opts) require_arg path "$1" "$2" && jvm_opts_file="$2" && shift 2 ;; + + -D*) addJava "$1" && shift ;; + -J*) addJava "${1:2}" && shift ;; + -S*) addScalac "${1:2}" && shift ;; + -28) setScalaVersion "$latest_28" && shift ;; + -29) setScalaVersion "$latest_29" && shift ;; + -210) setScalaVersion "$latest_210" && shift ;; + -211) setScalaVersion "$latest_211" && shift ;; + + *) addResidual "$1" && shift ;; + esac + done +} + +# process the direct command line arguments +process_args "$@" + +# skip #-styled comments and blank lines +readConfigFile() { + while read line; do + [[ $line =~ ^# ]] || [[ -z $line ]] || echo "$line" + done < "$1" +} + +# if there are file/environment sbt_opts, process again so we +# can supply args to this runner +if [[ -r "$sbt_opts_file" ]]; then + vlog "Using sbt options defined in file $sbt_opts_file" + while read opt; do extra_sbt_opts+=("$opt"); done < <(readConfigFile "$sbt_opts_file") +elif [[ -n "$SBT_OPTS" && ! ("$SBT_OPTS" =~ ^@.*) ]]; then + vlog "Using sbt options defined in variable \$SBT_OPTS" + extra_sbt_opts=( $SBT_OPTS ) +else + vlog "No extra sbt options have been defined" +fi + +[[ -n "${extra_sbt_opts[*]}" ]] && process_args "${extra_sbt_opts[@]}" + +# reset "$@" to the residual args +set -- "${residual_args[@]}" +argumentCount=$# + +# set sbt version +set_sbt_version + +# only exists in 0.12+ +setTraceLevel() { + case "$sbt_version" in + "0.7."* | "0.10."* | "0.11."* ) echoerr "Cannot set trace level in sbt version $sbt_version" ;; + *) setThisBuild traceLevel $trace_level ;; + esac +} + +# set scalacOptions if we were given any -S opts +[[ ${#scalac_args[@]} -eq 0 ]] || addSbt "set scalacOptions in ThisBuild += \"${scalac_args[@]}\"" + +# Update build.properties on disk to set explicit version - sbt gives us no choice +[[ -n "$sbt_explicit_version" ]] && update_build_props_sbt "$sbt_explicit_version" +vlog "Detected sbt version $sbt_version" + +[[ -n "$scala_version" ]] && vlog "Overriding scala version to $scala_version" + +# no args - alert them there's stuff in here +(( argumentCount > 0 )) || { + vlog "Starting $script_name: invoke with -help for other options" + residual_args=( shell ) +} + +# verify this is an sbt dir or -create was given +[[ -r ./build.sbt || -d ./project || -n "$sbt_create" ]] || { + cat < + + + org.scalatra.servlet.ScalatraListener + + + + default + /*.html + /css/* + /js/*.js + /images/* + + diff --git a/modules/swagger-codegen/src/main/resources/swagger-static/assets/css/bootstrap-responsive.css b/modules/swagger-codegen/src/main/resources/swagger-static/assets/css/bootstrap-responsive.css new file mode 100644 index 00000000000..a3352d774ce --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/swagger-static/assets/css/bootstrap-responsive.css @@ -0,0 +1,1092 @@ +/*! + * Bootstrap Responsive v2.2.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +@-ms-viewport { + width: device-width; +} + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + line-height: 0; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.hidden { + display: none; + visibility: hidden; +} + +.visible-phone { + display: none !important; +} + +.visible-tablet { + display: none !important; +} + +.hidden-desktop { + display: none !important; +} + +.visible-desktop { + display: inherit !important; +} + +@media (min-width: 768px) and (max-width: 979px) { + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important ; + } + .visible-tablet { + display: inherit !important; + } + .hidden-tablet { + display: none !important; + } +} + +@media (max-width: 767px) { + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important; + } + .visible-phone { + display: inherit !important; + } + .hidden-phone { + display: none !important; + } +} + +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + line-height: 0; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + min-height: 1px; + margin-left: 30px; + } + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 1170px; + } + .span12 { + width: 1170px; + } + .span11 { + width: 1070px; + } + .span10 { + width: 970px; + } + .span9 { + width: 870px; + } + .span8 { + width: 770px; + } + .span7 { + width: 670px; + } + .span6 { + width: 570px; + } + .span5 { + width: 470px; + } + .span4 { + width: 370px; + } + .span3 { + width: 270px; + } + .span2 { + width: 170px; + } + .span1 { + width: 70px; + } + .offset12 { + margin-left: 1230px; + } + .offset11 { + margin-left: 1130px; + } + .offset10 { + margin-left: 1030px; + } + .offset9 { + margin-left: 930px; + } + .offset8 { + margin-left: 830px; + } + .offset7 { + margin-left: 730px; + } + .offset6 { + margin-left: 630px; + } + .offset5 { + margin-left: 530px; + } + .offset4 { + margin-left: 430px; + } + .offset3 { + margin-left: 330px; + } + .offset2 { + margin-left: 230px; + } + .offset1 { + margin-left: 130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + line-height: 0; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.564102564102564%; + *margin-left: 2.5109110747408616%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.564102564102564%; + } + .row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; + } + .row-fluid .span11 { + width: 91.45299145299145%; + *width: 91.39979996362975%; + } + .row-fluid .span10 { + width: 82.90598290598291%; + *width: 82.8527914166212%; + } + .row-fluid .span9 { + width: 74.35897435897436%; + *width: 74.30578286961266%; + } + .row-fluid .span8 { + width: 65.81196581196582%; + *width: 65.75877432260411%; + } + .row-fluid .span7 { + width: 57.26495726495726%; + *width: 57.21176577559556%; + } + .row-fluid .span6 { + width: 48.717948717948715%; + *width: 48.664757228587014%; + } + .row-fluid .span5 { + width: 40.17094017094017%; + *width: 40.11774868157847%; + } + .row-fluid .span4 { + width: 31.623931623931625%; + *width: 31.570740134569924%; + } + .row-fluid .span3 { + width: 23.076923076923077%; + *width: 23.023731587561375%; + } + .row-fluid .span2 { + width: 14.52991452991453%; + *width: 14.476723040552828%; + } + .row-fluid .span1 { + width: 5.982905982905983%; + *width: 5.929714493544281%; + } + .row-fluid .offset12 { + margin-left: 105.12820512820512%; + *margin-left: 105.02182214948171%; + } + .row-fluid .offset12:first-child { + margin-left: 102.56410256410257%; + *margin-left: 102.45771958537915%; + } + .row-fluid .offset11 { + margin-left: 96.58119658119658%; + *margin-left: 96.47481360247316%; + } + .row-fluid .offset11:first-child { + margin-left: 94.01709401709402%; + *margin-left: 93.91071103837061%; + } + .row-fluid .offset10 { + margin-left: 88.03418803418803%; + *margin-left: 87.92780505546462%; + } + .row-fluid .offset10:first-child { + margin-left: 85.47008547008548%; + *margin-left: 85.36370249136206%; + } + .row-fluid .offset9 { + margin-left: 79.48717948717949%; + *margin-left: 79.38079650845607%; + } + .row-fluid .offset9:first-child { + margin-left: 76.92307692307693%; + *margin-left: 76.81669394435352%; + } + .row-fluid .offset8 { + margin-left: 70.94017094017094%; + *margin-left: 70.83378796144753%; + } + .row-fluid .offset8:first-child { + margin-left: 68.37606837606839%; + *margin-left: 68.26968539734497%; + } + .row-fluid .offset7 { + margin-left: 62.393162393162385%; + *margin-left: 62.28677941443899%; + } + .row-fluid .offset7:first-child { + margin-left: 59.82905982905982%; + *margin-left: 59.72267685033642%; + } + .row-fluid .offset6 { + margin-left: 53.84615384615384%; + *margin-left: 53.739770867430444%; + } + .row-fluid .offset6:first-child { + margin-left: 51.28205128205128%; + *margin-left: 51.175668303327875%; + } + .row-fluid .offset5 { + margin-left: 45.299145299145295%; + *margin-left: 45.1927623204219%; + } + .row-fluid .offset5:first-child { + margin-left: 42.73504273504273%; + *margin-left: 42.62865975631933%; + } + .row-fluid .offset4 { + margin-left: 36.75213675213675%; + *margin-left: 36.645753773413354%; + } + .row-fluid .offset4:first-child { + margin-left: 34.18803418803419%; + *margin-left: 34.081651209310785%; + } + .row-fluid .offset3 { + margin-left: 28.205128205128204%; + *margin-left: 28.0987452264048%; + } + .row-fluid .offset3:first-child { + margin-left: 25.641025641025642%; + *margin-left: 25.53464266230224%; + } + .row-fluid .offset2 { + margin-left: 19.65811965811966%; + *margin-left: 19.551736679396257%; + } + .row-fluid .offset2:first-child { + margin-left: 17.094017094017094%; + *margin-left: 16.98763411529369%; + } + .row-fluid .offset1 { + margin-left: 11.11111111111111%; + *margin-left: 11.004728132387708%; + } + .row-fluid .offset1:first-child { + margin-left: 8.547008547008547%; + *margin-left: 8.440625568285142%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 30px; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 1156px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 1056px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 956px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 856px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 756px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 656px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 556px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 456px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 356px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 256px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 156px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 56px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } + .row-fluid .thumbnails { + margin-left: 0; + } +} + +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + line-height: 0; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + min-height: 1px; + margin-left: 20px; + } + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 724px; + } + .span12 { + width: 724px; + } + .span11 { + width: 662px; + } + .span10 { + width: 600px; + } + .span9 { + width: 538px; + } + .span8 { + width: 476px; + } + .span7 { + width: 414px; + } + .span6 { + width: 352px; + } + .span5 { + width: 290px; + } + .span4 { + width: 228px; + } + .span3 { + width: 166px; + } + .span2 { + width: 104px; + } + .span1 { + width: 42px; + } + .offset12 { + margin-left: 764px; + } + .offset11 { + margin-left: 702px; + } + .offset10 { + margin-left: 640px; + } + .offset9 { + margin-left: 578px; + } + .offset8 { + margin-left: 516px; + } + .offset7 { + margin-left: 454px; + } + .offset6 { + margin-left: 392px; + } + .offset5 { + margin-left: 330px; + } + .offset4 { + margin-left: 268px; + } + .offset3 { + margin-left: 206px; + } + .offset2 { + margin-left: 144px; + } + .offset1 { + margin-left: 82px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + line-height: 0; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.7624309392265194%; + *margin-left: 2.709239449864817%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.7624309392265194%; + } + .row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; + } + .row-fluid .span11 { + width: 91.43646408839778%; + *width: 91.38327259903608%; + } + .row-fluid .span10 { + width: 82.87292817679558%; + *width: 82.81973668743387%; + } + .row-fluid .span9 { + width: 74.30939226519337%; + *width: 74.25620077583166%; + } + .row-fluid .span8 { + width: 65.74585635359117%; + *width: 65.69266486422946%; + } + .row-fluid .span7 { + width: 57.18232044198895%; + *width: 57.12912895262725%; + } + .row-fluid .span6 { + width: 48.61878453038674%; + *width: 48.56559304102504%; + } + .row-fluid .span5 { + width: 40.05524861878453%; + *width: 40.00205712942283%; + } + .row-fluid .span4 { + width: 31.491712707182323%; + *width: 31.43852121782062%; + } + .row-fluid .span3 { + width: 22.92817679558011%; + *width: 22.87498530621841%; + } + .row-fluid .span2 { + width: 14.3646408839779%; + *width: 14.311449394616199%; + } + .row-fluid .span1 { + width: 5.801104972375691%; + *width: 5.747913483013988%; + } + .row-fluid .offset12 { + margin-left: 105.52486187845304%; + *margin-left: 105.41847889972962%; + } + .row-fluid .offset12:first-child { + margin-left: 102.76243093922652%; + *margin-left: 102.6560479605031%; + } + .row-fluid .offset11 { + margin-left: 96.96132596685082%; + *margin-left: 96.8549429881274%; + } + .row-fluid .offset11:first-child { + margin-left: 94.1988950276243%; + *margin-left: 94.09251204890089%; + } + .row-fluid .offset10 { + margin-left: 88.39779005524862%; + *margin-left: 88.2914070765252%; + } + .row-fluid .offset10:first-child { + margin-left: 85.6353591160221%; + *margin-left: 85.52897613729868%; + } + .row-fluid .offset9 { + margin-left: 79.8342541436464%; + *margin-left: 79.72787116492299%; + } + .row-fluid .offset9:first-child { + margin-left: 77.07182320441989%; + *margin-left: 76.96544022569647%; + } + .row-fluid .offset8 { + margin-left: 71.2707182320442%; + *margin-left: 71.16433525332079%; + } + .row-fluid .offset8:first-child { + margin-left: 68.50828729281768%; + *margin-left: 68.40190431409427%; + } + .row-fluid .offset7 { + margin-left: 62.70718232044199%; + *margin-left: 62.600799341718584%; + } + .row-fluid .offset7:first-child { + margin-left: 59.94475138121547%; + *margin-left: 59.838368402492065%; + } + .row-fluid .offset6 { + margin-left: 54.14364640883978%; + *margin-left: 54.037263430116376%; + } + .row-fluid .offset6:first-child { + margin-left: 51.38121546961326%; + *margin-left: 51.27483249088986%; + } + .row-fluid .offset5 { + margin-left: 45.58011049723757%; + *margin-left: 45.47372751851417%; + } + .row-fluid .offset5:first-child { + margin-left: 42.81767955801105%; + *margin-left: 42.71129657928765%; + } + .row-fluid .offset4 { + margin-left: 37.01657458563536%; + *margin-left: 36.91019160691196%; + } + .row-fluid .offset4:first-child { + margin-left: 34.25414364640884%; + *margin-left: 34.14776066768544%; + } + .row-fluid .offset3 { + margin-left: 28.45303867403315%; + *margin-left: 28.346655695309746%; + } + .row-fluid .offset3:first-child { + margin-left: 25.69060773480663%; + *margin-left: 25.584224756083227%; + } + .row-fluid .offset2 { + margin-left: 19.88950276243094%; + *margin-left: 19.783119783707537%; + } + .row-fluid .offset2:first-child { + margin-left: 17.12707182320442%; + *margin-left: 17.02068884448102%; + } + .row-fluid .offset1 { + margin-left: 11.32596685082873%; + *margin-left: 11.219583872105325%; + } + .row-fluid .offset1:first-child { + margin-left: 8.56353591160221%; + *margin-left: 8.457152932878806%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 20px; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 710px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 648px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 586px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 524px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 462px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 400px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 338px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 276px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 214px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 152px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 90px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 28px; + } +} + +@media (max-width: 767px) { + body { + padding-right: 20px; + padding-left: 20px; + } + .navbar-fixed-top, + .navbar-fixed-bottom, + .navbar-static-top { + margin-right: -20px; + margin-left: -20px; + } + .container-fluid { + padding: 0; + } + .dl-horizontal dt { + float: none; + width: auto; + clear: none; + text-align: left; + } + .dl-horizontal dd { + margin-left: 0; + } + .container { + width: auto; + } + .row-fluid { + width: 100%; + } + .row, + .thumbnails { + margin-left: 0; + } + .thumbnails > li { + float: none; + margin-left: 0; + } + [class*="span"], + .uneditable-input[class*="span"], + .row-fluid [class*="span"] { + display: block; + float: none; + width: 100%; + margin-left: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .span12, + .row-fluid .span12 { + width: 100%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="offset"]:first-child { + margin-left: 0; + } + .input-large, + .input-xlarge, + .input-xxlarge, + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .input-prepend input, + .input-append input, + .input-prepend input[class*="span"], + .input-append input[class*="span"] { + display: inline-block; + width: auto; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 0; + } + .modal { + position: fixed; + top: 20px; + right: 20px; + left: 20px; + width: auto; + margin: 0; + } + .modal.fade { + top: -100px; + } + .modal.fade.in { + top: 20px; + } +} + +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 20px; + } + input[type="checkbox"], + input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-right: 10px; + padding-left: 10px; + } + .media .pull-left, + .media .pull-right { + display: block; + float: none; + margin-bottom: 10px; + } + .media-object { + margin-right: 0; + margin-left: 0; + } + .modal { + top: 10px; + right: 10px; + left: 10px; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} + +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top, + .navbar-fixed-bottom { + position: static; + } + .navbar-fixed-top { + margin-bottom: 20px; + } + .navbar-fixed-bottom { + margin-top: 20px; + } + .navbar-fixed-top .navbar-inner, + .navbar-fixed-bottom .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-right: 10px; + padding-left: 10px; + margin: 0 0 0 -5px; + } + .nav-collapse { + clear: both; + } + .nav-collapse .nav { + float: none; + margin: 0 0 10px; + } + .nav-collapse .nav > li { + float: none; + } + .nav-collapse .nav > li > a { + margin-bottom: 2px; + } + .nav-collapse .nav > .divider-vertical { + display: none; + } + .nav-collapse .nav .nav-header { + color: #777777; + text-shadow: none; + } + .nav-collapse .nav > li > a, + .nav-collapse .dropdown-menu a { + padding: 9px 15px; + font-weight: bold; + color: #777777; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .nav-collapse .btn { + padding: 4px 10px 4px; + font-weight: normal; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + } + .nav-collapse .dropdown-menu li + li a { + margin-bottom: 2px; + } + .nav-collapse .nav > li > a:hover, + .nav-collapse .dropdown-menu a:hover { + background-color: #f2f2f2; + } + .navbar-inverse .nav-collapse .nav > li > a, + .navbar-inverse .nav-collapse .dropdown-menu a { + color: #999999; + } + .navbar-inverse .nav-collapse .nav > li > a:hover, + .navbar-inverse .nav-collapse .dropdown-menu a:hover { + background-color: #111111; + } + .nav-collapse.in .btn-group { + padding: 0; + margin-top: 5px; + } + .nav-collapse .dropdown-menu { + position: static; + top: auto; + left: auto; + display: none; + float: none; + max-width: none; + padding: 0; + margin: 0 15px; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .nav-collapse .open > .dropdown-menu { + display: block; + } + .nav-collapse .dropdown-menu:before, + .nav-collapse .dropdown-menu:after { + display: none; + } + .nav-collapse .dropdown-menu .divider { + display: none; + } + .nav-collapse .nav > li > .dropdown-menu:before, + .nav-collapse .nav > li > .dropdown-menu:after { + display: none; + } + .nav-collapse .navbar-form, + .nav-collapse .navbar-search { + float: none; + padding: 10px 15px; + margin: 10px 0; + border-top: 1px solid #f2f2f2; + border-bottom: 1px solid #f2f2f2; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar-inverse .nav-collapse .navbar-form, + .navbar-inverse .nav-collapse .navbar-search { + border-top-color: #111111; + border-bottom-color: #111111; + } + .navbar .nav-collapse .nav.pull-right { + float: none; + margin-left: 0; + } + .nav-collapse, + .nav-collapse.collapse { + height: 0; + overflow: hidden; + } + .navbar .btn-navbar { + display: block; + } + .navbar-static .navbar-inner { + padding-right: 10px; + padding-left: 10px; + } +} + +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + overflow: visible !important; + } +} diff --git a/modules/swagger-codegen/src/main/resources/swagger-static/assets/css/bootstrap.css b/modules/swagger-codegen/src/main/resources/swagger-static/assets/css/bootstrap.css new file mode 100644 index 00000000000..db3b3bfd6a0 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/swagger-static/assets/css/bootstrap.css @@ -0,0 +1,6057 @@ +/*! + * Bootstrap v2.2.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} + +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +audio:not([controls]) { + display: none; +} + +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +a:hover, +a:active { + outline: 0; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + width: auto\9; + height: auto; + max-width: 100%; + vertical-align: middle; + border: 0; + -ms-interpolation-mode: bicubic; +} + +#map_canvas img, +.google-maps img { + max-width: none; +} + +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} + +button, +input { + *overflow: visible; + line-height: normal; +} + +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} + +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} + +label, +select, +button, +input[type="button"], +input[type="reset"], +input[type="submit"], +input[type="radio"], +input[type="checkbox"] { + cursor: pointer; +} + +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} + +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} + +textarea { + overflow: auto; + vertical-align: top; +} + +@media print { + * { + color: #000 !important; + text-shadow: none !important; + background: transparent !important; + box-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + .ir a:after, + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + @page { + margin: 0.5cm; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } +} + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + line-height: 0; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 20px; + color: #333333; + background-color: #ffffff; +} + +a { + color: #0088cc; + text-decoration: none; +} + +a:hover { + color: #005580; + text-decoration: underline; +} + +.img-rounded { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.img-polaroid { + padding: 4px; + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} + +.img-circle { + -webkit-border-radius: 500px; + -moz-border-radius: 500px; + border-radius: 500px; +} + +.row { + margin-left: -20px; + *zoom: 1; +} + +.row:before, +.row:after { + display: table; + line-height: 0; + content: ""; +} + +.row:after { + clear: both; +} + +[class*="span"] { + float: left; + min-height: 1px; + margin-left: 20px; +} + +.container, +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.span12 { + width: 940px; +} + +.span11 { + width: 860px; +} + +.span10 { + width: 780px; +} + +.span9 { + width: 700px; +} + +.span8 { + width: 620px; +} + +.span7 { + width: 540px; +} + +.span6 { + width: 460px; +} + +.span5 { + width: 380px; +} + +.span4 { + width: 300px; +} + +.span3 { + width: 220px; +} + +.span2 { + width: 140px; +} + +.span1 { + width: 60px; +} + +.offset12 { + margin-left: 980px; +} + +.offset11 { + margin-left: 900px; +} + +.offset10 { + margin-left: 820px; +} + +.offset9 { + margin-left: 740px; +} + +.offset8 { + margin-left: 660px; +} + +.offset7 { + margin-left: 580px; +} + +.offset6 { + margin-left: 500px; +} + +.offset5 { + margin-left: 420px; +} + +.offset4 { + margin-left: 340px; +} + +.offset3 { + margin-left: 260px; +} + +.offset2 { + margin-left: 180px; +} + +.offset1 { + margin-left: 100px; +} + +.row-fluid { + width: 100%; + *zoom: 1; +} + +.row-fluid:before, +.row-fluid:after { + display: table; + line-height: 0; + content: ""; +} + +.row-fluid:after { + clear: both; +} + +.row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.127659574468085%; + *margin-left: 2.074468085106383%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.row-fluid [class*="span"]:first-child { + margin-left: 0; +} + +.row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.127659574468085%; +} + +.row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; +} + +.row-fluid .span11 { + width: 91.48936170212765%; + *width: 91.43617021276594%; +} + +.row-fluid .span10 { + width: 82.97872340425532%; + *width: 82.92553191489361%; +} + +.row-fluid .span9 { + width: 74.46808510638297%; + *width: 74.41489361702126%; +} + +.row-fluid .span8 { + width: 65.95744680851064%; + *width: 65.90425531914893%; +} + +.row-fluid .span7 { + width: 57.44680851063829%; + *width: 57.39361702127659%; +} + +.row-fluid .span6 { + width: 48.93617021276595%; + *width: 48.88297872340425%; +} + +.row-fluid .span5 { + width: 40.42553191489362%; + *width: 40.37234042553192%; +} + +.row-fluid .span4 { + width: 31.914893617021278%; + *width: 31.861702127659576%; +} + +.row-fluid .span3 { + width: 23.404255319148934%; + *width: 23.351063829787233%; +} + +.row-fluid .span2 { + width: 14.893617021276595%; + *width: 14.840425531914894%; +} + +.row-fluid .span1 { + width: 6.382978723404255%; + *width: 6.329787234042553%; +} + +.row-fluid .offset12 { + margin-left: 104.25531914893617%; + *margin-left: 104.14893617021275%; +} + +.row-fluid .offset12:first-child { + margin-left: 102.12765957446808%; + *margin-left: 102.02127659574467%; +} + +.row-fluid .offset11 { + margin-left: 95.74468085106382%; + *margin-left: 95.6382978723404%; +} + +.row-fluid .offset11:first-child { + margin-left: 93.61702127659574%; + *margin-left: 93.51063829787232%; +} + +.row-fluid .offset10 { + margin-left: 87.23404255319149%; + *margin-left: 87.12765957446807%; +} + +.row-fluid .offset10:first-child { + margin-left: 85.1063829787234%; + *margin-left: 84.99999999999999%; +} + +.row-fluid .offset9 { + margin-left: 78.72340425531914%; + *margin-left: 78.61702127659572%; +} + +.row-fluid .offset9:first-child { + margin-left: 76.59574468085106%; + *margin-left: 76.48936170212764%; +} + +.row-fluid .offset8 { + margin-left: 70.2127659574468%; + *margin-left: 70.10638297872339%; +} + +.row-fluid .offset8:first-child { + margin-left: 68.08510638297872%; + *margin-left: 67.9787234042553%; +} + +.row-fluid .offset7 { + margin-left: 61.70212765957446%; + *margin-left: 61.59574468085106%; +} + +.row-fluid .offset7:first-child { + margin-left: 59.574468085106375%; + *margin-left: 59.46808510638297%; +} + +.row-fluid .offset6 { + margin-left: 53.191489361702125%; + *margin-left: 53.085106382978715%; +} + +.row-fluid .offset6:first-child { + margin-left: 51.063829787234035%; + *margin-left: 50.95744680851063%; +} + +.row-fluid .offset5 { + margin-left: 44.68085106382979%; + *margin-left: 44.57446808510638%; +} + +.row-fluid .offset5:first-child { + margin-left: 42.5531914893617%; + *margin-left: 42.4468085106383%; +} + +.row-fluid .offset4 { + margin-left: 36.170212765957444%; + *margin-left: 36.06382978723405%; +} + +.row-fluid .offset4:first-child { + margin-left: 34.04255319148936%; + *margin-left: 33.93617021276596%; +} + +.row-fluid .offset3 { + margin-left: 27.659574468085104%; + *margin-left: 27.5531914893617%; +} + +.row-fluid .offset3:first-child { + margin-left: 25.53191489361702%; + *margin-left: 25.425531914893618%; +} + +.row-fluid .offset2 { + margin-left: 19.148936170212764%; + *margin-left: 19.04255319148936%; +} + +.row-fluid .offset2:first-child { + margin-left: 17.02127659574468%; + *margin-left: 16.914893617021278%; +} + +.row-fluid .offset1 { + margin-left: 10.638297872340425%; + *margin-left: 10.53191489361702%; +} + +.row-fluid .offset1:first-child { + margin-left: 8.51063829787234%; + *margin-left: 8.404255319148938%; +} + +[class*="span"].hide, +.row-fluid [class*="span"].hide { + display: none; +} + +[class*="span"].pull-right, +.row-fluid [class*="span"].pull-right { + float: right; +} + +.container { + margin-right: auto; + margin-left: auto; + *zoom: 1; +} + +.container:before, +.container:after { + display: table; + line-height: 0; + content: ""; +} + +.container:after { + clear: both; +} + +.container-fluid { + padding-right: 20px; + padding-left: 20px; + *zoom: 1; +} + +.container-fluid:before, +.container-fluid:after { + display: table; + line-height: 0; + content: ""; +} + +.container-fluid:after { + clear: both; +} + +p { + margin: 0 0 10px; +} + +.lead { + margin-bottom: 20px; + font-size: 21px; + font-weight: 200; + line-height: 30px; +} + +small { + font-size: 85%; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +cite { + font-style: normal; +} + +.muted { + color: #999999; +} + +a.muted:hover { + color: #808080; +} + +.text-warning { + color: #c09853; +} + +a.text-warning:hover { + color: #a47e3c; +} + +.text-error { + color: #b94a48; +} + +a.text-error:hover { + color: #953b39; +} + +.text-info { + color: #3a87ad; +} + +a.text-info:hover { + color: #2d6987; +} + +.text-success { + color: #468847; +} + +a.text-success:hover { + color: #356635; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 10px 0; + font-family: inherit; + font-weight: bold; + line-height: 20px; + color: inherit; + text-rendering: optimizelegibility; +} + +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + line-height: 1; + color: #999999; +} + +h1, +h2, +h3 { + line-height: 40px; +} + +h1 { + font-size: 38.5px; +} + +h2 { + font-size: 31.5px; +} + +h3 { + font-size: 24.5px; +} + +h4 { + font-size: 17.5px; +} + +h5 { + font-size: 14px; +} + +h6 { + font-size: 11.9px; +} + +h1 small { + font-size: 24.5px; +} + +h2 small { + font-size: 17.5px; +} + +h3 small { + font-size: 14px; +} + +h4 small { + font-size: 14px; +} + +.page-header { + padding-bottom: 9px; + margin: 20px 0 30px; + border-bottom: 1px solid #eeeeee; +} + +ul, +ol { + padding: 0; + margin: 0 0 10px 25px; +} + +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} + +li { + line-height: 20px; +} + +ul.unstyled, +ol.unstyled { + margin-left: 0; + list-style: none; +} + +ul.inline, +ol.inline { + margin-left: 0; + list-style: none; +} + +ul.inline > li, +ol.inline > li { + display: inline-block; + padding-right: 5px; + padding-left: 5px; +} + +dl { + margin-bottom: 20px; +} + +dt, +dd { + line-height: 20px; +} + +dt { + font-weight: bold; +} + +dd { + margin-left: 10px; +} + +.dl-horizontal { + *zoom: 1; +} + +.dl-horizontal:before, +.dl-horizontal:after { + display: table; + line-height: 0; + content: ""; +} + +.dl-horizontal:after { + clear: both; +} + +.dl-horizontal dt { + float: left; + width: 160px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +.dl-horizontal dd { + margin-left: 180px; +} + +hr { + margin: 20px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} + +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #999999; +} + +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} + +blockquote { + padding: 0 0 0 15px; + margin: 0 0 20px; + border-left: 5px solid #eeeeee; +} + +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 25px; +} + +blockquote small { + display: block; + line-height: 20px; + color: #999999; +} + +blockquote small:before { + content: '\2014 \00A0'; +} + +blockquote.pull-right { + float: right; + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; +} + +blockquote.pull-right p, +blockquote.pull-right small { + text-align: right; +} + +blockquote.pull-right small:before { + content: ''; +} + +blockquote.pull-right small:after { + content: '\00A0 \2014'; +} + +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +address { + display: block; + margin-bottom: 20px; + font-style: normal; + line-height: 20px; +} + +code, +pre { + padding: 0 3px 2px; + font-family: Monaco, Menlo, Consolas, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +code { + padding: 2px 4px; + color: #d14; + white-space: nowrap; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} + +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 20px; + word-break: break-all; + word-wrap: break-word; + white-space: pre; + white-space: pre-wrap; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +pre.prettyprint { + margin-bottom: 20px; +} + +pre code { + padding: 0; + color: inherit; + white-space: pre; + white-space: pre-wrap; + background-color: transparent; + border: 0; +} + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} + +form { + margin: 0 0 20px; +} + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: 40px; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} + +legend small { + font-size: 15px; + color: #999999; +} + +label, +input, +button, +select, +textarea { + font-size: 14px; + font-weight: normal; + line-height: 20px; +} + +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +label { + display: block; + margin-bottom: 5px; +} + +select, +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + display: inline-block; + height: 20px; + padding: 4px 6px; + margin-bottom: 10px; + font-size: 14px; + line-height: 20px; + color: #555555; + vertical-align: middle; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +input, +textarea, +.uneditable-input { + width: 206px; +} + +textarea { + height: auto; +} + +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + background-color: #ffffff; + border: 1px solid #cccccc; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} + +textarea:focus, +input[type="text"]:focus, +input[type="password"]:focus, +input[type="datetime"]:focus, +input[type="datetime-local"]:focus, +input[type="date"]:focus, +input[type="month"]:focus, +input[type="time"]:focus, +input[type="week"]:focus, +input[type="number"]:focus, +input[type="email"]:focus, +input[type="url"]:focus, +input[type="search"]:focus, +input[type="tel"]:focus, +input[type="color"]:focus, +.uneditable-input:focus { + border-color: rgba(82, 168, 236, 0.8); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); +} + +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + *margin-top: 0; + line-height: normal; +} + +input[type="file"], +input[type="image"], +input[type="submit"], +input[type="reset"], +input[type="button"], +input[type="radio"], +input[type="checkbox"] { + width: auto; +} + +select, +input[type="file"] { + height: 30px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 30px; +} + +select { + width: 220px; + background-color: #ffffff; + border: 1px solid #cccccc; +} + +select[multiple], +select[size] { + height: auto; +} + +select:focus, +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.uneditable-input, +.uneditable-textarea { + color: #999999; + cursor: not-allowed; + background-color: #fcfcfc; + border-color: #cccccc; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); +} + +.uneditable-input { + overflow: hidden; + white-space: nowrap; +} + +.uneditable-textarea { + width: auto; + height: auto; +} + +input:-moz-placeholder, +textarea:-moz-placeholder { + color: #999999; +} + +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: #999999; +} + +input::-webkit-input-placeholder, +textarea::-webkit-input-placeholder { + color: #999999; +} + +.radio, +.checkbox { + min-height: 20px; + padding-left: 20px; +} + +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + float: left; + margin-left: -20px; +} + +.controls > .radio:first-child, +.controls > .checkbox:first-child { + padding-top: 5px; +} + +.radio.inline, +.checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} + +.radio.inline + .radio.inline, +.checkbox.inline + .checkbox.inline { + margin-left: 10px; +} + +.input-mini { + width: 60px; +} + +.input-small { + width: 90px; +} + +.input-medium { + width: 150px; +} + +.input-large { + width: 210px; +} + +.input-xlarge { + width: 270px; +} + +.input-xxlarge { + width: 530px; +} + +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"] { + float: none; + margin-left: 0; +} + +.input-append input[class*="span"], +.input-append .uneditable-input[class*="span"], +.input-prepend input[class*="span"], +.input-prepend .uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"], +.row-fluid .input-prepend [class*="span"], +.row-fluid .input-append [class*="span"] { + display: inline-block; +} + +input, +textarea, +.uneditable-input { + margin-left: 0; +} + +.controls-row [class*="span"] + [class*="span"] { + margin-left: 20px; +} + +input.span12, +textarea.span12, +.uneditable-input.span12 { + width: 926px; +} + +input.span11, +textarea.span11, +.uneditable-input.span11 { + width: 846px; +} + +input.span10, +textarea.span10, +.uneditable-input.span10 { + width: 766px; +} + +input.span9, +textarea.span9, +.uneditable-input.span9 { + width: 686px; +} + +input.span8, +textarea.span8, +.uneditable-input.span8 { + width: 606px; +} + +input.span7, +textarea.span7, +.uneditable-input.span7 { + width: 526px; +} + +input.span6, +textarea.span6, +.uneditable-input.span6 { + width: 446px; +} + +input.span5, +textarea.span5, +.uneditable-input.span5 { + width: 366px; +} + +input.span4, +textarea.span4, +.uneditable-input.span4 { + width: 286px; +} + +input.span3, +textarea.span3, +.uneditable-input.span3 { + width: 206px; +} + +input.span2, +textarea.span2, +.uneditable-input.span2 { + width: 126px; +} + +input.span1, +textarea.span1, +.uneditable-input.span1 { + width: 46px; +} + +.controls-row { + *zoom: 1; +} + +.controls-row:before, +.controls-row:after { + display: table; + line-height: 0; + content: ""; +} + +.controls-row:after { + clear: both; +} + +.controls-row [class*="span"], +.row-fluid .controls-row [class*="span"] { + float: left; +} + +.controls-row .checkbox[class*="span"], +.controls-row .radio[class*="span"] { + padding-top: 5px; +} + +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + cursor: not-allowed; + background-color: #eeeeee; +} + +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"][readonly], +input[type="checkbox"][readonly] { + background-color: transparent; +} + +.control-group.warning .control-label, +.control-group.warning .help-block, +.control-group.warning .help-inline { + color: #c09853; +} + +.control-group.warning .checkbox, +.control-group.warning .radio, +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + color: #c09853; +} + +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + border-color: #c09853; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.warning input:focus, +.control-group.warning select:focus, +.control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; +} + +.control-group.warning .input-prepend .add-on, +.control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} + +.control-group.error .control-label, +.control-group.error .help-block, +.control-group.error .help-inline { + color: #b94a48; +} + +.control-group.error .checkbox, +.control-group.error .radio, +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + color: #b94a48; +} + +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + border-color: #b94a48; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.error input:focus, +.control-group.error select:focus, +.control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; +} + +.control-group.error .input-prepend .add-on, +.control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} + +.control-group.success .control-label, +.control-group.success .help-block, +.control-group.success .help-inline { + color: #468847; +} + +.control-group.success .checkbox, +.control-group.success .radio, +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + color: #468847; +} + +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + border-color: #468847; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.success input:focus, +.control-group.success select:focus, +.control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; +} + +.control-group.success .input-prepend .add-on, +.control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} + +.control-group.info .control-label, +.control-group.info .help-block, +.control-group.info .help-inline { + color: #3a87ad; +} + +.control-group.info .checkbox, +.control-group.info .radio, +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + color: #3a87ad; +} + +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + border-color: #3a87ad; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.info input:focus, +.control-group.info select:focus, +.control-group.info textarea:focus { + border-color: #2d6987; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; +} + +.control-group.info .input-prepend .add-on, +.control-group.info .input-append .add-on { + color: #3a87ad; + background-color: #d9edf7; + border-color: #3a87ad; +} + +input:focus:invalid, +textarea:focus:invalid, +select:focus:invalid { + color: #b94a48; + border-color: #ee5f5b; +} + +input:focus:invalid:focus, +textarea:focus:invalid:focus, +select:focus:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} + +.form-actions { + padding: 19px 20px 20px; + margin-top: 20px; + margin-bottom: 20px; + background-color: #f5f5f5; + border-top: 1px solid #e5e5e5; + *zoom: 1; +} + +.form-actions:before, +.form-actions:after { + display: table; + line-height: 0; + content: ""; +} + +.form-actions:after { + clear: both; +} + +.help-block, +.help-inline { + color: #595959; +} + +.help-block { + display: block; + margin-bottom: 10px; +} + +.help-inline { + display: inline-block; + *display: inline; + padding-left: 5px; + vertical-align: middle; + *zoom: 1; +} + +.input-append, +.input-prepend { + margin-bottom: 5px; + font-size: 0; + white-space: nowrap; +} + +.input-append input, +.input-prepend input, +.input-append select, +.input-prepend select, +.input-append .uneditable-input, +.input-prepend .uneditable-input, +.input-append .dropdown-menu, +.input-prepend .dropdown-menu { + font-size: 14px; +} + +.input-append input, +.input-prepend input, +.input-append select, +.input-prepend select, +.input-append .uneditable-input, +.input-prepend .uneditable-input { + position: relative; + margin-bottom: 0; + *margin-left: 0; + vertical-align: top; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-append input:focus, +.input-prepend input:focus, +.input-append select:focus, +.input-prepend select:focus, +.input-append .uneditable-input:focus, +.input-prepend .uneditable-input:focus { + z-index: 2; +} + +.input-append .add-on, +.input-prepend .add-on { + display: inline-block; + width: auto; + height: 20px; + min-width: 16px; + padding: 4px 5px; + font-size: 14px; + font-weight: normal; + line-height: 20px; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #eeeeee; + border: 1px solid #ccc; +} + +.input-append .add-on, +.input-prepend .add-on, +.input-append .btn, +.input-prepend .btn, +.input-append .btn-group > .dropdown-toggle, +.input-prepend .btn-group > .dropdown-toggle { + vertical-align: top; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-append .active, +.input-prepend .active { + background-color: #a9dba9; + border-color: #46a546; +} + +.input-prepend .add-on, +.input-prepend .btn { + margin-right: -1px; +} + +.input-prepend .add-on:first-child, +.input-prepend .btn:first-child { + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.input-append input, +.input-append select, +.input-append .uneditable-input { + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.input-append input + .btn-group .btn:last-child, +.input-append select + .btn-group .btn:last-child, +.input-append .uneditable-input + .btn-group .btn:last-child { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-append .add-on, +.input-append .btn, +.input-append .btn-group { + margin-left: -1px; +} + +.input-append .add-on:last-child, +.input-append .btn:last-child, +.input-append .btn-group:last-child > .dropdown-toggle { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-prepend.input-append input, +.input-prepend.input-append select, +.input-prepend.input-append .uneditable-input { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-prepend.input-append input + .btn-group .btn, +.input-prepend.input-append select + .btn-group .btn, +.input-prepend.input-append .uneditable-input + .btn-group .btn { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-prepend.input-append .add-on:first-child, +.input-prepend.input-append .btn:first-child { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.input-prepend.input-append .add-on:last-child, +.input-prepend.input-append .btn:last-child { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-prepend.input-append .btn-group:first-child { + margin-left: 0; +} + +input.search-query { + padding-right: 14px; + padding-right: 4px \9; + padding-left: 14px; + padding-left: 4px \9; + /* IE7-8 doesn't have border-radius, so don't indent the padding */ + + margin-bottom: 0; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +/* Allow for input prepend/append in search forms */ + +.form-search .input-append .search-query, +.form-search .input-prepend .search-query { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.form-search .input-append .search-query { + -webkit-border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; +} + +.form-search .input-append .btn { + -webkit-border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; +} + +.form-search .input-prepend .search-query { + -webkit-border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; +} + +.form-search .input-prepend .btn { + -webkit-border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; +} + +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input, +.form-search .input-prepend, +.form-inline .input-prepend, +.form-horizontal .input-prepend, +.form-search .input-append, +.form-inline .input-append, +.form-horizontal .input-append { + display: inline-block; + *display: inline; + margin-bottom: 0; + vertical-align: middle; + *zoom: 1; +} + +.form-search .hide, +.form-inline .hide, +.form-horizontal .hide { + display: none; +} + +.form-search label, +.form-inline label, +.form-search .btn-group, +.form-inline .btn-group { + display: inline-block; +} + +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + margin-bottom: 0; +} + +.form-search .radio, +.form-search .checkbox, +.form-inline .radio, +.form-inline .checkbox { + padding-left: 0; + margin-bottom: 0; + vertical-align: middle; +} + +.form-search .radio input[type="radio"], +.form-search .checkbox input[type="checkbox"], +.form-inline .radio input[type="radio"], +.form-inline .checkbox input[type="checkbox"] { + float: left; + margin-right: 3px; + margin-left: 0; +} + +.control-group { + margin-bottom: 10px; +} + +legend + .control-group { + margin-top: 20px; + -webkit-margin-top-collapse: separate; +} + +.form-horizontal .control-group { + margin-bottom: 20px; + *zoom: 1; +} + +.form-horizontal .control-group:before, +.form-horizontal .control-group:after { + display: table; + line-height: 0; + content: ""; +} + +.form-horizontal .control-group:after { + clear: both; +} + +.form-horizontal .control-label { + float: left; + width: 160px; + padding-top: 5px; + text-align: right; +} + +.form-horizontal .controls { + *display: inline-block; + *padding-left: 20px; + margin-left: 180px; + *margin-left: 0; +} + +.form-horizontal .controls:first-child { + *padding-left: 180px; +} + +.form-horizontal .help-block { + margin-bottom: 0; +} + +.form-horizontal input + .help-block, +.form-horizontal select + .help-block, +.form-horizontal textarea + .help-block, +.form-horizontal .uneditable-input + .help-block, +.form-horizontal .input-prepend + .help-block, +.form-horizontal .input-append + .help-block { + margin-top: 10px; +} + +.form-horizontal .form-actions { + padding-left: 180px; +} + +table { + max-width: 100%; + background-color: transparent; + border-collapse: collapse; + border-spacing: 0; +} + +.table, table { + width: 100%; + margin-bottom: 20px; +} + +.table th, +table th, +.table td, +table td { + padding: 8px; + line-height: 20px; + text-align: left; + vertical-align: top; + border-top: 1px solid #dddddd; +} + +.table th, +table th { + font-weight: bold; +} + +.table thead th, +table thead th { + vertical-align: bottom; +} + +.table caption + thead tr:first-child th, +.table caption + thead tr:first-child td, +.table colgroup + thead tr:first-child th, +.table colgroup + thead tr:first-child td, +.table thead:first-child tr:first-child th, +.table thead:first-child tr:first-child td, +table caption + thead tr:first-child th, +table caption + thead tr:first-child td, +table colgroup + thead tr:first-child th, +table colgroup + thead tr:first-child td, +table thead:first-child tr:first-child th, +table thead:first-child tr:first-child td { + border-top: 0; +} + +.table tbody + tbody, +table tbody + tbody { + border-top: 2px solid #dddddd; +} + +.table .table, +table table { + background-color: #ffffff; +} + +.table-condensed th, +.table-condensed td { + padding: 4px 5px; +} + +.table-bordered { + border: 1px solid #dddddd; + border-collapse: separate; + *border-collapse: collapse; + border-left: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.table-bordered th, +.table-bordered td { + border-left: 1px solid #dddddd; +} + +.table-bordered caption + thead tr:first-child th, +.table-bordered caption + tbody tr:first-child th, +.table-bordered caption + tbody tr:first-child td, +.table-bordered colgroup + thead tr:first-child th, +.table-bordered colgroup + tbody tr:first-child th, +.table-bordered colgroup + tbody tr:first-child td, +.table-bordered thead:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} + +.table-bordered thead:first-child tr:first-child > th:first-child, +.table-bordered tbody:first-child tr:first-child > td:first-child { + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.table-bordered thead:first-child tr:first-child > th:last-child, +.table-bordered tbody:first-child tr:first-child > td:last-child { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; +} + +.table-bordered thead:last-child tr:last-child > th:first-child, +.table-bordered tbody:last-child tr:last-child > td:first-child, +.table-bordered tfoot:last-child tr:last-child > td:first-child { + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; +} + +.table-bordered thead:last-child tr:last-child > th:last-child, +.table-bordered tbody:last-child tr:last-child > td:last-child, +.table-bordered tfoot:last-child tr:last-child > td:last-child { + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; +} + +.table-bordered tfoot + tbody:last-child tr:last-child td:first-child { + -webkit-border-bottom-left-radius: 0; + border-bottom-left-radius: 0; + -moz-border-radius-bottomleft: 0; +} + +.table-bordered tfoot + tbody:last-child tr:last-child td:last-child { + -webkit-border-bottom-right-radius: 0; + border-bottom-right-radius: 0; + -moz-border-radius-bottomright: 0; +} + +.table-bordered caption + thead tr:first-child th:first-child, +.table-bordered caption + tbody tr:first-child td:first-child, +.table-bordered colgroup + thead tr:first-child th:first-child, +.table-bordered colgroup + tbody tr:first-child td:first-child { + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.table-bordered caption + thead tr:first-child th:last-child, +.table-bordered caption + tbody tr:first-child td:last-child, +.table-bordered colgroup + thead tr:first-child th:last-child, +.table-bordered colgroup + tbody tr:first-child td:last-child { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; +} + +.table-striped tbody > tr:nth-child(odd) > td, +.table-striped tbody > tr:nth-child(odd) > th, +table tbody > tr:nth-child(odd) > td, +table tbody > tr:nth-child(odd) > th { + background-color: #f9f9f9; +} + +.table-hover tbody tr:hover td, +.table-hover tbody tr:hover th { + background-color: #f5f5f5; +} + +table td[class*="span"], +table th[class*="span"], +.row-fluid table td[class*="span"], +.row-fluid table th[class*="span"] { + display: table-cell; + float: none; + margin-left: 0; +} + +.table td.span1, +.table th.span1 { + float: none; + width: 44px; + margin-left: 0; +} + +.table td.span2, +.table th.span2 { + float: none; + width: 124px; + margin-left: 0; +} + +.table td.span3, +.table th.span3 { + float: none; + width: 204px; + margin-left: 0; +} + +.table td.span4, +.table th.span4 { + float: none; + width: 284px; + margin-left: 0; +} + +.table td.span5, +.table th.span5 { + float: none; + width: 364px; + margin-left: 0; +} + +.table td.span6, +.table th.span6 { + float: none; + width: 444px; + margin-left: 0; +} + +.table td.span7, +.table th.span7 { + float: none; + width: 524px; + margin-left: 0; +} + +.table td.span8, +.table th.span8 { + float: none; + width: 604px; + margin-left: 0; +} + +.table td.span9, +.table th.span9 { + float: none; + width: 684px; + margin-left: 0; +} + +.table td.span10, +.table th.span10 { + float: none; + width: 764px; + margin-left: 0; +} + +.table td.span11, +.table th.span11 { + float: none; + width: 844px; + margin-left: 0; +} + +.table td.span12, +.table th.span12 { + float: none; + width: 924px; + margin-left: 0; +} + +.table tbody tr.success td, +table tbody tr.success td { + background-color: #dff0d8; +} + +.table tbody tr.error td, +table tbody tr.error td { + background-color: #f2dede; +} + +.table tbody tr.warning td, +table tbody tr.warning td { + background-color: #fcf8e3; +} + +.table tbody tr.info td, +table tbody tr.info td { + background-color: #d9edf7; +} + +.table-hover tbody tr.success:hover td { + background-color: #d0e9c6; +} + +.table-hover tbody tr.error:hover td { + background-color: #ebcccc; +} + +.table-hover tbody tr.warning:hover td { + background-color: #faf2cc; +} + +.table-hover tbody tr.info:hover td { + background-color: #c4e3f3; +} + +[class^="icon-"], +[class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + margin-top: 1px; + *margin-right: .3em; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; +} + +/* White icons with optional class, or on hover/active states of certain elements */ + +.icon-white, +.nav-pills > .active > a > [class^="icon-"], +.nav-pills > .active > a > [class*=" icon-"], +.nav-list > .active > a > [class^="icon-"], +.nav-list > .active > a > [class*=" icon-"], +.navbar-inverse .nav > .active > a > [class^="icon-"], +.navbar-inverse .nav > .active > a > [class*=" icon-"], +.dropdown-menu > li > a:hover > [class^="icon-"], +.dropdown-menu > li > a:hover > [class*=" icon-"], +.dropdown-menu > .active > a > [class^="icon-"], +.dropdown-menu > .active > a > [class*=" icon-"], +.dropdown-submenu:hover > a > [class^="icon-"], +.dropdown-submenu:hover > a > [class*=" icon-"] { + background-image: url("../img/glyphicons-halflings-white.png"); +} + +.icon-glass { + background-position: 0 0; +} + +.icon-music { + background-position: -24px 0; +} + +.icon-search { + background-position: -48px 0; +} + +.icon-envelope { + background-position: -72px 0; +} + +.icon-heart { + background-position: -96px 0; +} + +.icon-star { + background-position: -120px 0; +} + +.icon-star-empty { + background-position: -144px 0; +} + +.icon-user { + background-position: -168px 0; +} + +.icon-film { + background-position: -192px 0; +} + +.icon-th-large { + background-position: -216px 0; +} + +.icon-th { + background-position: -240px 0; +} + +.icon-th-list { + background-position: -264px 0; +} + +.icon-ok { + background-position: -288px 0; +} + +.icon-remove { + background-position: -312px 0; +} + +.icon-zoom-in { + background-position: -336px 0; +} + +.icon-zoom-out { + background-position: -360px 0; +} + +.icon-off { + background-position: -384px 0; +} + +.icon-signal { + background-position: -408px 0; +} + +.icon-cog { + background-position: -432px 0; +} + +.icon-trash { + background-position: -456px 0; +} + +.icon-home { + background-position: 0 -24px; +} + +.icon-file { + background-position: -24px -24px; +} + +.icon-time { + background-position: -48px -24px; +} + +.icon-road { + background-position: -72px -24px; +} + +.icon-download-alt { + background-position: -96px -24px; +} + +.icon-download { + background-position: -120px -24px; +} + +.icon-upload { + background-position: -144px -24px; +} + +.icon-inbox { + background-position: -168px -24px; +} + +.icon-play-circle { + background-position: -192px -24px; +} + +.icon-repeat { + background-position: -216px -24px; +} + +.icon-refresh { + background-position: -240px -24px; +} + +.icon-list-alt { + background-position: -264px -24px; +} + +.icon-lock { + background-position: -287px -24px; +} + +.icon-flag { + background-position: -312px -24px; +} + +.icon-headphones { + background-position: -336px -24px; +} + +.icon-volume-off { + background-position: -360px -24px; +} + +.icon-volume-down { + background-position: -384px -24px; +} + +.icon-volume-up { + background-position: -408px -24px; +} + +.icon-qrcode { + background-position: -432px -24px; +} + +.icon-barcode { + background-position: -456px -24px; +} + +.icon-tag { + background-position: 0 -48px; +} + +.icon-tags { + background-position: -25px -48px; +} + +.icon-book { + background-position: -48px -48px; +} + +.icon-bookmark { + background-position: -72px -48px; +} + +.icon-print { + background-position: -96px -48px; +} + +.icon-camera { + background-position: -120px -48px; +} + +.icon-font { + background-position: -144px -48px; +} + +.icon-bold { + background-position: -167px -48px; +} + +.icon-italic { + background-position: -192px -48px; +} + +.icon-text-height { + background-position: -216px -48px; +} + +.icon-text-width { + background-position: -240px -48px; +} + +.icon-align-left { + background-position: -264px -48px; +} + +.icon-align-center { + background-position: -288px -48px; +} + +.icon-align-right { + background-position: -312px -48px; +} + +.icon-align-justify { + background-position: -336px -48px; +} + +.icon-list { + background-position: -360px -48px; +} + +.icon-indent-left { + background-position: -384px -48px; +} + +.icon-indent-right { + background-position: -408px -48px; +} + +.icon-facetime-video { + background-position: -432px -48px; +} + +.icon-picture { + background-position: -456px -48px; +} + +.icon-pencil { + background-position: 0 -72px; +} + +.icon-map-marker { + background-position: -24px -72px; +} + +.icon-adjust { + background-position: -48px -72px; +} + +.icon-tint { + background-position: -72px -72px; +} + +.icon-edit { + background-position: -96px -72px; +} + +.icon-share { + background-position: -120px -72px; +} + +.icon-check { + background-position: -144px -72px; +} + +.icon-move { + background-position: -168px -72px; +} + +.icon-step-backward { + background-position: -192px -72px; +} + +.icon-fast-backward { + background-position: -216px -72px; +} + +.icon-backward { + background-position: -240px -72px; +} + +.icon-play { + background-position: -264px -72px; +} + +.icon-pause { + background-position: -288px -72px; +} + +.icon-stop { + background-position: -312px -72px; +} + +.icon-forward { + background-position: -336px -72px; +} + +.icon-fast-forward { + background-position: -360px -72px; +} + +.icon-step-forward { + background-position: -384px -72px; +} + +.icon-eject { + background-position: -408px -72px; +} + +.icon-chevron-left { + background-position: -432px -72px; +} + +.icon-chevron-right { + background-position: -456px -72px; +} + +.icon-plus-sign { + background-position: 0 -96px; +} + +.icon-minus-sign { + background-position: -24px -96px; +} + +.icon-remove-sign { + background-position: -48px -96px; +} + +.icon-ok-sign { + background-position: -72px -96px; +} + +.icon-question-sign { + background-position: -96px -96px; +} + +.icon-info-sign { + background-position: -120px -96px; +} + +.icon-screenshot { + background-position: -144px -96px; +} + +.icon-remove-circle { + background-position: -168px -96px; +} + +.icon-ok-circle { + background-position: -192px -96px; +} + +.icon-ban-circle { + background-position: -216px -96px; +} + +.icon-arrow-left { + background-position: -240px -96px; +} + +.icon-arrow-right { + background-position: -264px -96px; +} + +.icon-arrow-up { + background-position: -289px -96px; +} + +.icon-arrow-down { + background-position: -312px -96px; +} + +.icon-share-alt { + background-position: -336px -96px; +} + +.icon-resize-full { + background-position: -360px -96px; +} + +.icon-resize-small { + background-position: -384px -96px; +} + +.icon-plus { + background-position: -408px -96px; +} + +.icon-minus { + background-position: -433px -96px; +} + +.icon-asterisk { + background-position: -456px -96px; +} + +.icon-exclamation-sign { + background-position: 0 -120px; +} + +.icon-gift { + background-position: -24px -120px; +} + +.icon-leaf { + background-position: -48px -120px; +} + +.icon-fire { + background-position: -72px -120px; +} + +.icon-eye-open { + background-position: -96px -120px; +} + +.icon-eye-close { + background-position: -120px -120px; +} + +.icon-warning-sign { + background-position: -144px -120px; +} + +.icon-plane { + background-position: -168px -120px; +} + +.icon-calendar { + background-position: -192px -120px; +} + +.icon-random { + width: 16px; + background-position: -216px -120px; +} + +.icon-comment { + background-position: -240px -120px; +} + +.icon-magnet { + background-position: -264px -120px; +} + +.icon-chevron-up { + background-position: -288px -120px; +} + +.icon-chevron-down { + background-position: -313px -119px; +} + +.icon-retweet { + background-position: -336px -120px; +} + +.icon-shopping-cart { + background-position: -360px -120px; +} + +.icon-folder-close { + background-position: -384px -120px; +} + +.icon-folder-open { + width: 16px; + background-position: -408px -120px; +} + +.icon-resize-vertical { + background-position: -432px -119px; +} + +.icon-resize-horizontal { + background-position: -456px -118px; +} + +.icon-hdd { + background-position: 0 -144px; +} + +.icon-bullhorn { + background-position: -24px -144px; +} + +.icon-bell { + background-position: -48px -144px; +} + +.icon-certificate { + background-position: -72px -144px; +} + +.icon-thumbs-up { + background-position: -96px -144px; +} + +.icon-thumbs-down { + background-position: -120px -144px; +} + +.icon-hand-right { + background-position: -144px -144px; +} + +.icon-hand-left { + background-position: -168px -144px; +} + +.icon-hand-up { + background-position: -192px -144px; +} + +.icon-hand-down { + background-position: -216px -144px; +} + +.icon-circle-arrow-right { + background-position: -240px -144px; +} + +.icon-circle-arrow-left { + background-position: -264px -144px; +} + +.icon-circle-arrow-up { + background-position: -288px -144px; +} + +.icon-circle-arrow-down { + background-position: -312px -144px; +} + +.icon-globe { + background-position: -336px -144px; +} + +.icon-wrench { + background-position: -360px -144px; +} + +.icon-tasks { + background-position: -384px -144px; +} + +.icon-filter { + background-position: -408px -144px; +} + +.icon-briefcase { + background-position: -432px -144px; +} + +.icon-fullscreen { + background-position: -456px -144px; +} + +.dropup, +.dropdown { + position: relative; +} + +.dropdown-toggle { + *margin-bottom: -3px; +} + +.dropdown-toggle:active, +.open .dropdown-toggle { + outline: 0; +} + +.caret { + display: inline-block; + width: 0; + height: 0; + vertical-align: top; + border-top: 4px solid #000000; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + content: ""; +} + +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + *border-right-width: 2px; + *border-bottom-width: 2px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.dropdown-menu .divider { + *width: 100%; + height: 1px; + margin: 9px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.dropdown-menu li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 20px; + color: #333333; + white-space: nowrap; +} + +.dropdown-menu li > a:hover, +.dropdown-menu li > a:focus, +.dropdown-submenu:hover > a { + color: #ffffff; + text-decoration: none; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #0077b3); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); +} + +.dropdown-menu .active > a, +.dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #0077b3); + background-repeat: repeat-x; + outline: 0; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); +} + +.dropdown-menu .disabled > a, +.dropdown-menu .disabled > a:hover { + color: #999999; +} + +.dropdown-menu .disabled > a:hover { + text-decoration: none; + cursor: default; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.open { + *z-index: 1000; +} + +.open > .dropdown-menu { + display: block; +} + +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} + +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px solid #000000; + content: ""; +} + +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} + +.dropdown-submenu { + position: relative; +} + +.dropdown-submenu > .dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + -webkit-border-radius: 0 6px 6px 6px; + -moz-border-radius: 0 6px 6px 6px; + border-radius: 0 6px 6px 6px; +} + +.dropdown-submenu:hover > .dropdown-menu { + display: block; +} + +.dropup .dropdown-submenu > .dropdown-menu { + top: auto; + bottom: 0; + margin-top: 0; + margin-bottom: -2px; + -webkit-border-radius: 5px 5px 5px 0; + -moz-border-radius: 5px 5px 5px 0; + border-radius: 5px 5px 5px 0; +} + +.dropdown-submenu > a:after { + display: block; + float: right; + width: 0; + height: 0; + margin-top: 5px; + margin-right: -10px; + border-color: transparent; + border-left-color: #cccccc; + border-style: solid; + border-width: 5px 0 5px 5px; + content: " "; +} + +.dropdown-submenu:hover > a:after { + border-left-color: #ffffff; +} + +.dropdown-submenu.pull-left { + float: none; +} + +.dropdown-submenu.pull-left > .dropdown-menu { + left: -100%; + margin-left: 10px; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} + +.dropdown .dropdown-menu .nav-header { + padding-right: 20px; + padding-left: 20px; +} + +.typeahead { + z-index: 1051; + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} + +.well-large { + padding: 24px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.well-small { + padding: 9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} + +.fade.in { + opacity: 1; +} + +.collapse { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; +} + +.collapse.in { + height: auto; +} + +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 20px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} + +.close:hover { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.4; + filter: alpha(opacity=40); +} + +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} + +.btn { + display: inline-block; + *display: inline; + padding: 4px 12px; + margin-bottom: 0; + *margin-left: .3em; + font-size: 14px; + line-height: 20px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + cursor: pointer; + background-color: #f5f5f5; + *background-color: #e6e6e6; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); + background-repeat: repeat-x; + border: 1px solid #bbbbbb; + *border: 0; + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + border-bottom-color: #a2a2a2; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + color: #333333; + background-color: #e6e6e6; + *background-color: #d9d9d9; +} + +.btn:active, +.btn.active { + background-color: #cccccc \9; +} + +.btn:first-child { + *margin-left: 0; +} + +.btn:hover { + color: #333333; + text-decoration: none; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} + +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.btn.active, +.btn:active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn.disabled, +.btn[disabled] { + cursor: default; + background-image: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-large { + padding: 11px 19px; + font-size: 17.5px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.btn-large [class^="icon-"], +.btn-large [class*=" icon-"] { + margin-top: 4px; +} + +.btn-small { + padding: 2px 10px; + font-size: 11.9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.btn-small [class^="icon-"], +.btn-small [class*=" icon-"] { + margin-top: 0; +} + +.btn-mini [class^="icon-"], +.btn-mini [class*=" icon-"] { + margin-top: -1px; +} + +.btn-mini { + padding: 0 6px; + font-size: 10.5px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.btn-block { + display: block; + width: 100%; + padding-right: 0; + padding-left: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.btn-block + .btn-block { + margin-top: 5px; +} + +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} + +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-inverse.active { + color: rgba(255, 255, 255, 0.75); +} + +.btn { + border-color: #c5c5c5; + border-color: rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25); +} + +.btn-primary { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #006dcc; + *background-color: #0044cc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(to bottom, #0088cc, #0044cc); + background-repeat: repeat-x; + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + color: #ffffff; + background-color: #0044cc; + *background-color: #003bb3; +} + +.btn-primary:active, +.btn-primary.active { + background-color: #003399 \9; +} + +.btn-warning { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #faa732; + *background-color: #f89406; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(to bottom, #fbb450, #f89406); + background-repeat: repeat-x; + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + color: #ffffff; + background-color: #f89406; + *background-color: #df8505; +} + +.btn-warning:active, +.btn-warning.active { + background-color: #c67605 \9; +} + +.btn-danger { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #da4f49; + *background-color: #bd362f; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(to bottom, #ee5f5b, #bd362f); + background-repeat: repeat-x; + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + color: #ffffff; + background-color: #bd362f; + *background-color: #a9302a; +} + +.btn-danger:active, +.btn-danger.active { + background-color: #942a25 \9; +} + +.btn-success { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #5bb75b; + *background-color: #51a351; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(to bottom, #62c462, #51a351); + background-repeat: repeat-x; + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + color: #ffffff; + background-color: #51a351; + *background-color: #499249; +} + +.btn-success:active, +.btn-success.active { + background-color: #408140 \9; +} + +.btn-info { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #49afcd; + *background-color: #2f96b4; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(to bottom, #5bc0de, #2f96b4); + background-repeat: repeat-x; + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + color: #ffffff; + background-color: #2f96b4; + *background-color: #2a85a0; +} + +.btn-info:active, +.btn-info.active { + background-color: #24748c \9; +} + +.btn-inverse { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #363636; + *background-color: #222222; + background-image: -moz-linear-gradient(top, #444444, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222)); + background-image: -webkit-linear-gradient(top, #444444, #222222); + background-image: -o-linear-gradient(top, #444444, #222222); + background-image: linear-gradient(to bottom, #444444, #222222); + background-repeat: repeat-x; + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + color: #ffffff; + background-color: #222222; + *background-color: #151515; +} + +.btn-inverse:active, +.btn-inverse.active { + background-color: #080808 \9; +} + +button.btn, +input[type="submit"].btn { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn::-moz-focus-inner, +input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} + +button.btn.btn-large, +input[type="submit"].btn.btn-large { + *padding-top: 7px; + *padding-bottom: 7px; +} + +button.btn.btn-small, +input[type="submit"].btn.btn-small { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn.btn-mini, +input[type="submit"].btn.btn-mini { + *padding-top: 1px; + *padding-bottom: 1px; +} + +.btn-link, +.btn-link:active, +.btn-link[disabled] { + background-color: transparent; + background-image: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-link { + color: #0088cc; + cursor: pointer; + border-color: transparent; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-link:hover { + color: #005580; + text-decoration: underline; + background-color: transparent; +} + +.btn-link[disabled]:hover { + color: #333333; + text-decoration: none; +} + +.btn-group { + position: relative; + display: inline-block; + *display: inline; + *margin-left: .3em; + font-size: 0; + white-space: nowrap; + vertical-align: middle; + *zoom: 1; +} + +.btn-group:first-child { + *margin-left: 0; +} + +.btn-group + .btn-group { + margin-left: 5px; +} + +.btn-toolbar { + margin-top: 10px; + margin-bottom: 10px; + font-size: 0; +} + +.btn-toolbar > .btn + .btn, +.btn-toolbar > .btn-group + .btn, +.btn-toolbar > .btn + .btn-group { + margin-left: 5px; +} + +.btn-group > .btn { + position: relative; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group > .btn + .btn { + margin-left: -1px; +} + +.btn-group > .btn, +.btn-group > .dropdown-menu, +.btn-group > .popover { + font-size: 14px; +} + +.btn-group > .btn-mini { + font-size: 10.5px; +} + +.btn-group > .btn-small { + font-size: 11.9px; +} + +.btn-group > .btn-large { + font-size: 17.5px; +} + +.btn-group > .btn:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 4px; +} + +.btn-group > .btn:last-child, +.btn-group > .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; +} + +.btn-group > .btn.large:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.btn-group > .btn.large:last-child, +.btn-group > .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active { + z-index: 2; +} + +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + +.btn-group > .btn + .dropdown-toggle { + *padding-top: 5px; + padding-right: 8px; + *padding-bottom: 5px; + padding-left: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group > .btn-mini + .dropdown-toggle { + *padding-top: 2px; + padding-right: 5px; + *padding-bottom: 2px; + padding-left: 5px; +} + +.btn-group > .btn-small + .dropdown-toggle { + *padding-top: 5px; + *padding-bottom: 4px; +} + +.btn-group > .btn-large + .dropdown-toggle { + *padding-top: 7px; + padding-right: 12px; + *padding-bottom: 7px; + padding-left: 12px; +} + +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group.open .btn.dropdown-toggle { + background-color: #e6e6e6; +} + +.btn-group.open .btn-primary.dropdown-toggle { + background-color: #0044cc; +} + +.btn-group.open .btn-warning.dropdown-toggle { + background-color: #f89406; +} + +.btn-group.open .btn-danger.dropdown-toggle { + background-color: #bd362f; +} + +.btn-group.open .btn-success.dropdown-toggle { + background-color: #51a351; +} + +.btn-group.open .btn-info.dropdown-toggle { + background-color: #2f96b4; +} + +.btn-group.open .btn-inverse.dropdown-toggle { + background-color: #222222; +} + +.btn .caret { + margin-top: 8px; + margin-left: 0; +} + +.btn-mini .caret, +.btn-small .caret, +.btn-large .caret { + margin-top: 6px; +} + +.btn-large .caret { + border-top-width: 5px; + border-right-width: 5px; + border-left-width: 5px; +} + +.dropup .btn-large .caret { + border-bottom-width: 5px; +} + +.btn-primary .caret, +.btn-warning .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.btn-group-vertical { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} + +.btn-group-vertical > .btn { + display: block; + float: none; + max-width: 100%; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group-vertical > .btn + .btn { + margin-top: -1px; + margin-left: 0; +} + +.btn-group-vertical > .btn:first-child { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.btn-group-vertical > .btn:last-child { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.btn-group-vertical > .btn-large:first-child { + -webkit-border-radius: 6px 6px 0 0; + -moz-border-radius: 6px 6px 0 0; + border-radius: 6px 6px 0 0; +} + +.btn-group-vertical > .btn-large:last-child { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} + +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 20px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.alert, +.alert h4 { + color: #c09853; +} + +.alert h4 { + margin: 0; +} + +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 20px; +} + +.alert-success { + color: #468847; + background-color: #dff0d8; + border-color: #d6e9c6; +} + +.alert-success h4 { + color: #468847; +} + +.alert-danger, +.alert-error { + color: #b94a48; + background-color: #f2dede; + border-color: #eed3d7; +} + +.alert-danger h4, +.alert-error h4 { + color: #b94a48; +} + +.alert-info { + color: #3a87ad; + background-color: #d9edf7; + border-color: #bce8f1; +} + +.alert-info h4 { + color: #3a87ad; +} + +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} + +.alert-block > p, +.alert-block > ul { + margin-bottom: 0; +} + +.alert-block p + p { + margin-top: 5px; +} + +.nav { + margin-bottom: 20px; + margin-left: 0; + list-style: none; +} + +.nav > li > a { + display: block; +} + +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} + +.nav > li > a > img { + max-width: none; +} + +.nav > .pull-right { + float: right; +} + +.nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 20px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} + +.nav li + .nav-header { + margin-top: 9px; +} + +.nav-list { + padding-right: 15px; + padding-left: 15px; + margin-bottom: 0; +} + +.nav-list > li > a, +.nav-list .nav-header { + margin-right: -15px; + margin-left: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} + +.nav-list > li > a { + padding: 3px 15px; +} + +.nav-list > .active > a, +.nav-list > .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} + +.nav-list [class^="icon-"], +.nav-list [class*=" icon-"] { + margin-right: 2px; +} + +.nav-list .divider { + *width: 100%; + height: 1px; + margin: 9px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.nav-tabs, +.nav-pills { + *zoom: 1; +} + +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + line-height: 0; + content: ""; +} + +.nav-tabs:after, +.nav-pills:after { + clear: both; +} + +.nav-tabs > li, +.nav-pills > li { + float: left; +} + +.nav-tabs > li > a, +.nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} + +.nav-tabs { + border-bottom: 1px solid #ddd; +} + +.nav-tabs > li { + margin-bottom: -1px; +} + +.nav-tabs > li > a { + padding-top: 8px; + padding-bottom: 8px; + line-height: 20px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} + +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover { + color: #555555; + cursor: default; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; +} + +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.nav-pills > .active > a, +.nav-pills > .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} + +.nav-stacked > li { + float: none; +} + +.nav-stacked > li > a { + margin-right: 0; +} + +.nav-tabs.nav-stacked { + border-bottom: 0; +} + +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-topleft: 4px; +} + +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-bottomright: 4px; + -moz-border-radius-bottomleft: 4px; +} + +.nav-tabs.nav-stacked > li > a:hover { + z-index: 2; + border-color: #ddd; +} + +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} + +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} + +.nav-tabs .dropdown-menu { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} + +.nav-pills .dropdown-menu { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.nav .dropdown-toggle .caret { + margin-top: 6px; + border-top-color: #0088cc; + border-bottom-color: #0088cc; +} + +.nav .dropdown-toggle:hover .caret { + border-top-color: #005580; + border-bottom-color: #005580; +} + +/* move down carets for tabs */ + +.nav-tabs .dropdown-toggle .caret { + margin-top: 8px; +} + +.nav .active .dropdown-toggle .caret { + border-top-color: #fff; + border-bottom-color: #fff; +} + +.nav-tabs .active .dropdown-toggle .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} + +.nav > .dropdown.active > a:hover { + cursor: pointer; +} + +.nav-tabs .open .dropdown-toggle, +.nav-pills .open .dropdown-toggle, +.nav > li.dropdown.open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} + +.nav li.dropdown.open .caret, +.nav li.dropdown.open.active .caret, +.nav li.dropdown.open a:hover .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} + +.tabs-stacked .open > a:hover { + border-color: #999999; +} + +.tabbable { + *zoom: 1; +} + +.tabbable:before, +.tabbable:after { + display: table; + line-height: 0; + content: ""; +} + +.tabbable:after { + clear: both; +} + +.tab-content { + overflow: auto; +} + +.tabs-below > .nav-tabs, +.tabs-right > .nav-tabs, +.tabs-left > .nav-tabs { + border-bottom: 0; +} + +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} + +.tab-content > .active, +.pill-content > .active { + display: block; +} + +.tabs-below > .nav-tabs { + border-top: 1px solid #ddd; +} + +.tabs-below > .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} + +.tabs-below > .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.tabs-below > .nav-tabs > li > a:hover { + border-top-color: #ddd; + border-bottom-color: transparent; +} + +.tabs-below > .nav-tabs > .active > a, +.tabs-below > .nav-tabs > .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} + +.tabs-left > .nav-tabs > li, +.tabs-right > .nav-tabs > li { + float: none; +} + +.tabs-left > .nav-tabs > li > a, +.tabs-right > .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} + +.tabs-left > .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} + +.tabs-left > .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.tabs-left > .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} + +.tabs-left > .nav-tabs .active > a, +.tabs-left > .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} + +.tabs-right > .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} + +.tabs-right > .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.tabs-right > .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} + +.tabs-right > .nav-tabs .active > a, +.tabs-right > .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} + +.nav > .disabled > a { + color: #999999; +} + +.nav > .disabled > a:hover { + text-decoration: none; + cursor: default; + background-color: transparent; +} + +.navbar { + *position: relative; + *z-index: 2; + margin-bottom: 20px; + overflow: visible; +} + +.navbar-inner { + min-height: 40px; + padding-right: 20px; + padding-left: 20px; + background-color: #fafafa; + background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2)); + background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2); + background-image: -o-linear-gradient(top, #ffffff, #f2f2f2); + background-image: linear-gradient(to bottom, #ffffff, #f2f2f2); + background-repeat: repeat-x; + border: 1px solid #d4d4d4; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0); + *zoom: 1; + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); +} + +.navbar-inner:before, +.navbar-inner:after { + display: table; + line-height: 0; + content: ""; +} + +.navbar-inner:after { + clear: both; +} + +.navbar .container { + width: auto; +} + +.nav-collapse.collapse { + height: auto; + overflow: visible; +} + +.navbar .brand { + display: block; + float: left; + padding: 10px 20px 10px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + color: #777777; + text-shadow: 0 1px 0 #ffffff; +} + +.navbar .brand:hover { + text-decoration: none; +} + +.navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #777777; +} + +.navbar-link { + color: #777777; +} + +.navbar-link:hover { + color: #333333; +} + +.navbar .divider-vertical { + height: 40px; + margin: 0 9px; + border-right: 1px solid #ffffff; + border-left: 1px solid #f2f2f2; +} + +.navbar .btn, +.navbar .btn-group { + margin-top: 5px; +} + +.navbar .btn-group .btn, +.navbar .input-prepend .btn, +.navbar .input-append .btn { + margin-top: 0; +} + +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} + +.navbar-form:before, +.navbar-form:after { + display: table; + line-height: 0; + content: ""; +} + +.navbar-form:after { + clear: both; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .radio, +.navbar-form .checkbox { + margin-top: 5px; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .btn { + display: inline-block; + margin-bottom: 0; +} + +.navbar-form input[type="image"], +.navbar-form input[type="checkbox"], +.navbar-form input[type="radio"] { + margin-top: 3px; +} + +.navbar-form .input-append, +.navbar-form .input-prepend { + margin-top: 5px; + white-space: nowrap; +} + +.navbar-form .input-append input, +.navbar-form .input-prepend input { + margin-top: 0; +} + +.navbar-search { + position: relative; + float: left; + margin-top: 5px; + margin-bottom: 0; +} + +.navbar-search .search-query { + padding: 4px 14px; + margin-bottom: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.navbar-static-top { + position: static; + margin-bottom: 0; +} + +.navbar-static-top .navbar-inner { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; + margin-bottom: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + border-width: 0 0 1px; +} + +.navbar-fixed-bottom .navbar-inner { + border-width: 1px 0 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-fixed-bottom .navbar-inner { + padding-right: 0; + padding-left: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.navbar-fixed-top { + top: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + -webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); +} + +.navbar-fixed-bottom { + bottom: 0; +} + +.navbar-fixed-bottom .navbar-inner { + -webkit-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); +} + +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} + +.navbar .nav.pull-right { + float: right; + margin-right: 0; +} + +.navbar .nav > li { + float: left; +} + +.navbar .nav > li > a { + float: none; + padding: 10px 15px 10px; + color: #777777; + text-decoration: none; + text-shadow: 0 1px 0 #ffffff; +} + +.navbar .nav .dropdown-toggle .caret { + margin-top: 8px; +} + +.navbar .nav > li > a:focus, +.navbar .nav > li > a:hover { + color: #333333; + text-decoration: none; + background-color: transparent; +} + +.navbar .nav > .active > a, +.navbar .nav > .active > a:hover, +.navbar .nav > .active > a:focus { + color: #555555; + text-decoration: none; + background-color: #e5e5e5; + -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); +} + +.navbar .btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-right: 5px; + margin-left: 5px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #ededed; + *background-color: #e5e5e5; + background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5)); + background-image: -webkit-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: -o-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: linear-gradient(to bottom, #f2f2f2, #e5e5e5); + background-repeat: repeat-x; + border-color: #e5e5e5 #e5e5e5 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} + +.navbar .btn-navbar:hover, +.navbar .btn-navbar:active, +.navbar .btn-navbar.active, +.navbar .btn-navbar.disabled, +.navbar .btn-navbar[disabled] { + color: #ffffff; + background-color: #e5e5e5; + *background-color: #d9d9d9; +} + +.navbar .btn-navbar:active, +.navbar .btn-navbar.active { + background-color: #cccccc \9; +} + +.navbar .btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} + +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} + +.navbar .nav > li > .dropdown-menu:before { + position: absolute; + top: -7px; + left: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} + +.navbar .nav > li > .dropdown-menu:after { + position: absolute; + top: -6px; + left: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + border-left: 6px solid transparent; + content: ''; +} + +.navbar-fixed-bottom .nav > li > .dropdown-menu:before { + top: auto; + bottom: -7px; + border-top: 7px solid #ccc; + border-bottom: 0; + border-top-color: rgba(0, 0, 0, 0.2); +} + +.navbar-fixed-bottom .nav > li > .dropdown-menu:after { + top: auto; + bottom: -6px; + border-top: 6px solid #ffffff; + border-bottom: 0; +} + +.navbar .nav li.dropdown > a:hover .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} + +.navbar .nav li.dropdown.open > .dropdown-toggle, +.navbar .nav li.dropdown.active > .dropdown-toggle, +.navbar .nav li.dropdown.open.active > .dropdown-toggle { + color: #555555; + background-color: #e5e5e5; +} + +.navbar .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #777777; + border-bottom-color: #777777; +} + +.navbar .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} + +.navbar .pull-right > li > .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu:before, +.navbar .nav > li > .dropdown-menu.pull-right:before { + right: 12px; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu:after, +.navbar .nav > li > .dropdown-menu.pull-right:after { + right: 13px; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right .dropdown-menu { + right: 100%; + left: auto; + margin-right: -1px; + margin-left: 0; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} + +.navbar-inverse .navbar-inner { + background-color: #1b1b1b; + background-image: -moz-linear-gradient(top, #222222, #111111); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111)); + background-image: -webkit-linear-gradient(top, #222222, #111111); + background-image: -o-linear-gradient(top, #222222, #111111); + background-image: linear-gradient(to bottom, #222222, #111111); + background-repeat: repeat-x; + border-color: #252525; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0); +} + +.navbar-inverse .brand, +.navbar-inverse .nav > li > a { + color: #999999; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.navbar-inverse .brand:hover, +.navbar-inverse .nav > li > a:hover { + color: #ffffff; +} + +.navbar-inverse .brand { + color: #999999; +} + +.navbar-inverse .navbar-text { + color: #999999; +} + +.navbar-inverse .nav > li > a:focus, +.navbar-inverse .nav > li > a:hover { + color: #ffffff; + background-color: transparent; +} + +.navbar-inverse .nav .active > a, +.navbar-inverse .nav .active > a:hover, +.navbar-inverse .nav .active > a:focus { + color: #ffffff; + background-color: #111111; +} + +.navbar-inverse .navbar-link { + color: #999999; +} + +.navbar-inverse .navbar-link:hover { + color: #ffffff; +} + +.navbar-inverse .divider-vertical { + border-right-color: #222222; + border-left-color: #111111; +} + +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle, +.navbar-inverse .nav li.dropdown.active > .dropdown-toggle, +.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle { + color: #ffffff; + background-color: #111111; +} + +.navbar-inverse .nav li.dropdown > a:hover .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #999999; + border-bottom-color: #999999; +} + +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar-inverse .navbar-search .search-query { + color: #ffffff; + background-color: #515151; + border-color: #111111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; +} + +.navbar-inverse .navbar-search .search-query:-moz-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query:-ms-input-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query:focus, +.navbar-inverse .navbar-search .search-query.focused { + padding: 5px 15px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + outline: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); +} + +.navbar-inverse .btn-navbar { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e0e0e; + *background-color: #040404; + background-image: -moz-linear-gradient(top, #151515, #040404); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404)); + background-image: -webkit-linear-gradient(top, #151515, #040404); + background-image: -o-linear-gradient(top, #151515, #040404); + background-image: linear-gradient(to bottom, #151515, #040404); + background-repeat: repeat-x; + border-color: #040404 #040404 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.navbar-inverse .btn-navbar:hover, +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active, +.navbar-inverse .btn-navbar.disabled, +.navbar-inverse .btn-navbar[disabled] { + color: #ffffff; + background-color: #040404; + *background-color: #000000; +} + +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active { + background-color: #000000 \9; +} + +.breadcrumb { + padding: 8px 15px; + margin: 0 0 20px; + list-style: none; + background-color: #f5f5f5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.breadcrumb > li { + display: inline-block; + *display: inline; + text-shadow: 0 1px 0 #ffffff; + *zoom: 1; +} + +.breadcrumb > li > .divider { + padding: 0 5px; + color: #ccc; +} + +.breadcrumb > .active { + color: #999999; +} + +.pagination { + margin: 20px 0; +} + +.pagination ul { + display: inline-block; + *display: inline; + margin-bottom: 0; + margin-left: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + *zoom: 1; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.pagination ul > li { + display: inline; +} + +.pagination ul > li > a, +.pagination ul > li > span { + float: left; + padding: 4px 12px; + line-height: 20px; + text-decoration: none; + background-color: #ffffff; + border: 1px solid #dddddd; + border-left-width: 0; +} + +.pagination ul > li > a:hover, +.pagination ul > .active > a, +.pagination ul > .active > span { + background-color: #f5f5f5; +} + +.pagination ul > .active > a, +.pagination ul > .active > span { + color: #999999; + cursor: default; +} + +.pagination ul > .disabled > span, +.pagination ul > .disabled > a, +.pagination ul > .disabled > a:hover { + color: #999999; + cursor: default; + background-color: transparent; +} + +.pagination ul > li:first-child > a, +.pagination ul > li:first-child > span { + border-left-width: 1px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 4px; +} + +.pagination ul > li:last-child > a, +.pagination ul > li:last-child > span { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; +} + +.pagination-centered { + text-align: center; +} + +.pagination-right { + text-align: right; +} + +.pagination-large ul > li > a, +.pagination-large ul > li > span { + padding: 11px 19px; + font-size: 17.5px; +} + +.pagination-large ul > li:first-child > a, +.pagination-large ul > li:first-child > span { + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.pagination-large ul > li:last-child > a, +.pagination-large ul > li:last-child > span { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.pagination-mini ul > li:first-child > a, +.pagination-small ul > li:first-child > a, +.pagination-mini ul > li:first-child > span, +.pagination-small ul > li:first-child > span { + -webkit-border-bottom-left-radius: 3px; + border-bottom-left-radius: 3px; + -webkit-border-top-left-radius: 3px; + border-top-left-radius: 3px; + -moz-border-radius-bottomleft: 3px; + -moz-border-radius-topleft: 3px; +} + +.pagination-mini ul > li:last-child > a, +.pagination-small ul > li:last-child > a, +.pagination-mini ul > li:last-child > span, +.pagination-small ul > li:last-child > span { + -webkit-border-top-right-radius: 3px; + border-top-right-radius: 3px; + -webkit-border-bottom-right-radius: 3px; + border-bottom-right-radius: 3px; + -moz-border-radius-topright: 3px; + -moz-border-radius-bottomright: 3px; +} + +.pagination-small ul > li > a, +.pagination-small ul > li > span { + padding: 2px 10px; + font-size: 11.9px; +} + +.pagination-mini ul > li > a, +.pagination-mini ul > li > span { + padding: 0 6px; + font-size: 10.5px; +} + +.pager { + margin: 20px 0; + text-align: center; + list-style: none; + *zoom: 1; +} + +.pager:before, +.pager:after { + display: table; + line-height: 0; + content: ""; +} + +.pager:after { + clear: both; +} + +.pager li { + display: inline; +} + +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.pager li > a:hover { + text-decoration: none; + background-color: #f5f5f5; +} + +.pager .next > a, +.pager .next > span { + float: right; +} + +.pager .previous > a, +.pager .previous > span { + float: left; +} + +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > span { + color: #999999; + cursor: default; + background-color: #fff; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop, +.modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.modal { + position: fixed; + top: 10%; + left: 50%; + z-index: 1050; + width: 560px; + margin-left: -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + outline: none; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} + +.modal.fade { + top: -25%; + -webkit-transition: opacity 0.3s linear, top 0.3s ease-out; + -moz-transition: opacity 0.3s linear, top 0.3s ease-out; + -o-transition: opacity 0.3s linear, top 0.3s ease-out; + transition: opacity 0.3s linear, top 0.3s ease-out; +} + +.modal.fade.in { + top: 10%; +} + +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} + +.modal-header .close { + margin-top: 2px; +} + +.modal-header h3 { + margin: 0; + line-height: 30px; +} + +.modal-body { + position: relative; + max-height: 400px; + padding: 15px; + overflow-y: auto; +} + +.modal-form { + margin-bottom: 0; +} + +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + text-align: right; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + line-height: 0; + content: ""; +} + +.modal-footer:after { + clear: both; +} + +.modal-footer .btn + .btn { + margin-bottom: 0; + margin-left: 5px; +} + +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} + +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} + +.tooltip { + position: absolute; + z-index: 1030; + display: block; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); + visibility: visible; +} + +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.tooltip.top { + margin-top: -3px; +} + +.tooltip.right { + margin-left: 3px; +} + +.tooltip.bottom { + margin-top: 3px; +} + +.tooltip.left { + margin-left: -3px; +} + +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} + +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-top-color: #000000; + border-width: 5px 5px 0; +} + +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-right-color: #000000; + border-width: 5px 5px 5px 0; +} + +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-left-color: #000000; + border-width: 5px 0 5px 5px; +} + +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-bottom-color: #000000; + border-width: 0 5px 5px; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + width: 236px; + padding: 1px; + text-align: left; + white-space: normal; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.popover.top { + margin-top: -10px; +} + +.popover.right { + margin-left: 10px; +} + +.popover.bottom { + margin-top: 10px; +} + +.popover.left { + margin-left: -10px; +} + +.popover-title { + padding: 8px 14px; + margin: 0; + font-size: 14px; + font-weight: normal; + line-height: 18px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + -webkit-border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; +} + +.popover-content { + padding: 9px 14px; +} + +.popover .arrow, +.popover .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} + +.popover .arrow { + border-width: 11px; +} + +.popover .arrow:after { + border-width: 10px; + content: ""; +} + +.popover.top .arrow { + bottom: -11px; + left: 50%; + margin-left: -11px; + border-top-color: #999; + border-top-color: rgba(0, 0, 0, 0.25); + border-bottom-width: 0; +} + +.popover.top .arrow:after { + bottom: 1px; + margin-left: -10px; + border-top-color: #ffffff; + border-bottom-width: 0; +} + +.popover.right .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-right-color: #999; + border-right-color: rgba(0, 0, 0, 0.25); + border-left-width: 0; +} + +.popover.right .arrow:after { + bottom: -10px; + left: 1px; + border-right-color: #ffffff; + border-left-width: 0; +} + +.popover.bottom .arrow { + top: -11px; + left: 50%; + margin-left: -11px; + border-bottom-color: #999; + border-bottom-color: rgba(0, 0, 0, 0.25); + border-top-width: 0; +} + +.popover.bottom .arrow:after { + top: 1px; + margin-left: -10px; + border-bottom-color: #ffffff; + border-top-width: 0; +} + +.popover.left .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-left-color: #999; + border-left-color: rgba(0, 0, 0, 0.25); + border-right-width: 0; +} + +.popover.left .arrow:after { + right: 1px; + bottom: -10px; + border-left-color: #ffffff; + border-right-width: 0; +} + +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} + +.thumbnails:before, +.thumbnails:after { + display: table; + line-height: 0; + content: ""; +} + +.thumbnails:after { + clear: both; +} + +.row-fluid .thumbnails { + margin-left: 0; +} + +.thumbnails > li { + float: left; + margin-bottom: 20px; + margin-left: 20px; +} + +.thumbnail { + display: block; + padding: 4px; + line-height: 20px; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} + +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} + +.thumbnail > img { + display: block; + max-width: 100%; + margin-right: auto; + margin-left: auto; +} + +.thumbnail .caption { + padding: 9px; + color: #555555; +} + +.media, +.media-body { + overflow: hidden; + *overflow: visible; + zoom: 1; +} + +.media, +.media .media { + margin-top: 15px; +} + +.media:first-child { + margin-top: 0; +} + +.media-object { + display: block; +} + +.media-heading { + margin: 0 0 5px; +} + +.media .pull-left { + margin-right: 10px; +} + +.media .pull-right { + margin-left: 10px; +} + +.media-list { + margin-left: 0; + list-style: none; +} + +.label, +.badge { + display: inline-block; + padding: 2px 4px; + font-size: 11.844px; + font-weight: bold; + line-height: 14px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + white-space: nowrap; + vertical-align: baseline; + background-color: #999999; +} + +.label { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.badge { + padding-right: 9px; + padding-left: 9px; + -webkit-border-radius: 9px; + -moz-border-radius: 9px; + border-radius: 9px; +} + +.label:empty, +.badge:empty { + display: none; +} + +a.label:hover, +a.badge:hover { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +.label-important, +.badge-important { + background-color: #b94a48; +} + +.label-important[href], +.badge-important[href] { + background-color: #953b39; +} + +.label-warning, +.badge-warning { + background-color: #f89406; +} + +.label-warning[href], +.badge-warning[href] { + background-color: #c67605; +} + +.label-success, +.badge-success { + background-color: #468847; +} + +.label-success[href], +.badge-success[href] { + background-color: #356635; +} + +.label-info, +.badge-info { + background-color: #3a87ad; +} + +.label-info[href], +.badge-info[href] { + background-color: #2d6987; +} + +.label-inverse, +.badge-inverse { + background-color: #333333; +} + +.label-inverse[href], +.badge-inverse[href] { + background-color: #1a1a1a; +} + +.btn .label, +.btn .badge { + position: relative; + top: -1px; +} + +.btn-mini .label, +.btn-mini .badge { + top: 0; +} + +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-moz-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-ms-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-o-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} + +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +.progress { + height: 20px; + margin-bottom: 20px; + overflow: hidden; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.progress .bar { + float: left; + width: 0; + height: 100%; + font-size: 12px; + color: #ffffff; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(to bottom, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} + +.progress .bar + .bar { + -webkit-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); +} + +.progress-striped .bar { + background-color: #149bdf; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} + +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + +.progress-danger .bar, +.progress .bar-danger { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(to bottom, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0); +} + +.progress-danger.progress-striped .bar, +.progress-striped .bar-danger { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-success .bar, +.progress .bar-success { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(to bottom, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0); +} + +.progress-success.progress-striped .bar, +.progress-striped .bar-success { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-info .bar, +.progress .bar-info { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(to bottom, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0); +} + +.progress-info.progress-striped .bar, +.progress-striped .bar-info { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-warning .bar, +.progress .bar-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(to bottom, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); +} + +.progress-warning.progress-striped .bar, +.progress-striped .bar-warning { + background-color: #fbb450; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.accordion { + margin-bottom: 20px; +} + +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.accordion-heading { + border-bottom: 0; +} + +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} + +.accordion-toggle { + cursor: pointer; +} + +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} + +.carousel { + position: relative; + margin-bottom: 20px; + line-height: 1; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel-inner > .item { + position: relative; + display: none; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} + +.carousel-inner > .item > img { + display: block; + line-height: 1; +} + +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} + +.carousel-inner > .active { + left: 0; +} + +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} + +.carousel-inner > .next { + left: 100%; +} + +.carousel-inner > .prev { + left: -100%; +} + +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} + +.carousel-inner > .active.left { + left: -100%; +} + +.carousel-inner > .active.right { + left: 100%; +} + +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} + +.carousel-control.right { + right: 15px; + left: auto; +} + +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} + +.carousel-caption { + position: absolute; + right: 0; + bottom: 0; + left: 0; + padding: 15px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} + +.carousel-caption h4, +.carousel-caption p { + line-height: 20px; + color: #ffffff; +} + +.carousel-caption h4 { + margin: 0 0 5px; +} + +.carousel-caption p { + margin-bottom: 0; +} + +.hero-unit { + padding: 60px; + margin-bottom: 30px; + font-size: 18px; + font-weight: 200; + line-height: 30px; + color: inherit; + background-color: #eeeeee; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; + color: inherit; +} + +.hero-unit li { + line-height: 30px; +} + +.pull-right { + float: right; +} + +.pull-left { + float: left; +} + +.hide { + display: none; +} + +.show { + display: block; +} + +.invisible { + visibility: hidden; +} + +.affix { + position: fixed; +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/swagger-static/assets/css/site.css b/modules/swagger-codegen/src/main/resources/swagger-static/assets/css/site.css new file mode 100644 index 00000000000..2c4cd52d35f --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/swagger-static/assets/css/site.css @@ -0,0 +1 @@ +site.css \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/swagger-static/assets/css/style.css b/modules/swagger-codegen/src/main/resources/swagger-static/assets/css/style.css new file mode 100644 index 00000000000..b26d2ef13ca --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/swagger-static/assets/css/style.css @@ -0,0 +1,292 @@ +.line-numbers { + margin-right: 1.0em; +} + +.content { + padding-bottom: 100px; +} + +.column_header_name { + width: 150px; +} + +.column_header_path { + width: 350px; +} + +.column_header_name .column_header_param_type .column_header_data_type .column_header_return_type { + width: 200px; +} + +.expandable { + display: none; +} + +.main_content { + margin-top: 80px; + margin-left: 25px; + margin-right: 25px; +} + +.model { + float: left; +} + +.model-container { + float: left; + width: 500px; + padding: 0px; +} + +.model-detail-container { + clear: left; + float: left; + width: 500px; + margin-left: 40px; +} + +.model-detail-popup { + box-shadow: rgba(0, 0, 0, 0.2) 0 2px 8px 5px; + border-style: solid; + border-width: 1px; + border-color: black; + padding-left: 10px; + padding-right: 10px; + padding-top: 10px; + padding-bottom: 10px; + background-color: white; + opacity: 0.99; + z-index: 1; + overflow: scroll; + width: 400px; +} + +.model-detail-popup .code { + background-color: #E4F5FF; + font-family: monospace; + white-space: pre; + margin: 10px; + overflow: auto; +} + +.model-detail-popup h2 { + margin-top: 0px; + padding-top: 0px; +} + +.model-detail-popup li { + padding-bottom: 5px; +} + +.model-detail-popup .param-reqiured-true { + font-family: monospace; + font-weight: bold; + clear: left; + display: block; + float: left; + width: 100%; +} + +.model-detail-popup .param-required-false { + font-family: monospace; + clear: left; + display: block; + float: left; + width: 100%; +} + +.model-detail-popup .param-description { + margin-left: 50px; + float: left; +} + +.section-header { + border-bottom: 2px; + font-weight: bold; + font-size: 15px; + padding: 6px 0; + color: rgb(57,57,57); +} + +.content { + padding-top: 100px; +} + +.content h1 { + font-size: 43px; + text-align: center; + margin-top: 40px; + margin-bottom: 40px; +} + +.sidebar { + box-sizing: border-box; + float: left; + display: block; + width: 240px; + overflow: scroll; + position: fixed; +} + +.section-box { + border-bottom-style: solid; + border-bottom: 10px; +} + +.section-box ul li { + list-style: none; + margin-left: 0px; +} + +.non-sidebar { + box-sizing: border-box; + display: block; + margin-left: 240px; + margin-right: 0px; + width: 638px; +} + +.non-sidebar h2 { + clear: left; + padding-top: 20px; +} + +.param { + display: block; + float: left; + width: 220px; + clear: left; +} + +.param-description { + float: left; + font-family: 'Helvetica Neue', Arial, 'Liberation Sans', FreeSans, sans-serif; +} + +.param-optional-flag { + font-style: italic; +} + +.section { + font-weight: normal; + clear: left; +} + +.section a { + text-decoration: underline; +} + +.code { + background-color: #E4F5FF; + font-family: monospace; + white-space: pre; + margin: 10px; + overflow: auto; + width: 600px; +} + +.header { + position: fixed; + text-align: left; + background-color: black; + float: left; + top: 0; + width: 100%; + height: 70px auto; + padding-bottom: 20px; + box-shadow: rgba(0, 0, 0, 0.2) 0 2px 8px 5px; +} + +.top-bar h1 a { + width: auto; +} + +.top-bar h1#logo a { + width: auto; + display: block; + clear: none; + float: left; + background-position: left;; + color: white; + text-decoration: none; +} + +.top-bar ul li { + list-style: none; +} + +.top-bar h1#logo span { + display: block; + clear: none; + float: left; + padding-top: 10px; + padding-left: 10px; + margin: 0px; +} + +.top-bar h1#logo a span.light { + color: #ffc97a; + color: #666666; + padding-left: 0px; +} + +.top-bar ul#nav { + float: none; + clear: both; + overflow: hidden; + margin: 0; + padding: 0; + display: block; + float: right; + clear: none; +} + +.top-bar ul#nav li { + float: left; + clear: none; + margin: 0; + padding: 2px 10px; + border-right: 1px solid #dddddd; +} + +.top-bar ul#nav li:first-child, .top-bar ul#nav li.first { + padding-left: 0; +} + +.top-bar ul#nav li:last-child, .top-bar ul#nav li.last { + padding-right: 0; + border-right: none; +} + +.top-bar ul#nav li { + border: none; + padding: 0 5px; +} + +.top-bar ul#nav li a { + display: block; + padding: 8px 10px 8px 10px; + color: #999999; + text-decoration: none; +} + +.top-bar ul#nav li a.strong { + color: white; +} + +.top-bar ul#nav li a:active, .top-bar ul#nav li a.active, .top-bar ul#nav li a:hover { + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -o-border-radius: 4px; + -ms-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px; + background-image: -webkit-gradient(linear, 0% 100%, 0% 0%, color-stop(0%, #ff5401), color-stop(100%, #ffa014)); + background-image: -moz-linear-gradient(bottom, #ff5401 0%, #ffa014 100%); + background-image: linear-gradient(bottom, #ff5401 0%, #ffa014 100%); + color: white; +} + +.top-bar ul#nav:hover li { + border-color: #222222; +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/swagger-static/assets/images/logo.png b/modules/swagger-codegen/src/main/resources/swagger-static/assets/images/logo.png new file mode 100644 index 00000000000..209e5a473fc Binary files /dev/null and b/modules/swagger-codegen/src/main/resources/swagger-static/assets/images/logo.png differ diff --git a/modules/swagger-codegen/src/main/resources/swagger-static/assets/js/bootstrap.js b/modules/swagger-codegen/src/main/resources/swagger-static/assets/js/bootstrap.js new file mode 100644 index 00000000000..6c15a583296 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/swagger-static/assets/js/bootstrap.js @@ -0,0 +1,2159 @@ +/* =================================================== + * bootstrap-transition.js v2.2.2 + * http://twitter.github.com/bootstrap/javascript.html#transitions + * =================================================== + * Copyright 2012 Twitter, 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. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) + * ======================================================= */ + + $(function () { + + $.support.transition = (function () { + + var transitionEnd = (function () { + + var el = document.createElement('bootstrap') + , transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd' + , 'MozTransition' : 'transitionend' + , 'OTransition' : 'oTransitionEnd otransitionend' + , 'transition' : 'transitionend' + } + , name + + for (name in transEndEventNames){ + if (el.style[name] !== undefined) { + return transEndEventNames[name] + } + } + + }()) + + return transitionEnd && { + end: transitionEnd + } + + })() + + }) + +}(window.jQuery);/* ========================================================== + * bootstrap-alert.js v2.2.2 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, 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. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent.trigger(e = $.Event('close')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + var old = $.fn.alert + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT NO CONFLICT + * ================= */ + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + /* ALERT DATA-API + * ============== */ + + $(document).on('click.alert.data-api', dismiss, Alert.prototype.close) + +}(window.jQuery);/* ============================================================ + * bootstrap-button.js v2.2.2 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, 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. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + Button.prototype.toggle = function () { + var $parent = this.$element.closest('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + var old = $.fn.button + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON NO CONFLICT + * ================== */ + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + /* BUTTON DATA-API + * =============== */ + + $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + +}(window.jQuery);/* ========================================================== + * bootstrap-carousel.js v2.2.2 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, 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. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = options + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.prototype = { + + cycle: function (e) { + if (!e) this.paused = false + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.item.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function (e) { + if (!e) this.paused = true + if (this.$element.find('.next, .prev').length && $.support.transition.end) { + this.$element.trigger($.support.transition.end) + this.cycle() + } + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.item.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + , e + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + e = $.Event('slide', { + relatedTarget: $next[0] + }) + + if ($next.hasClass('active')) return + + if ($.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } else { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + var old = $.fn.carousel + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option) + , action = typeof option == 'string' ? option : options.slide + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + , pause: 'hover' + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL NO CONFLICT + * ==================== */ + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + /* CAROUSEL DATA-API + * ================= */ + + $(document).on('click.carousel.data-api', '[data-slide]', function (e) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + +}(window.jQuery);/* ============================================================= + * bootstrap-collapse.js v2.2.2 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, 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. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* COLLAPSE PUBLIC CLASS DEFINITION + * ================================ */ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options.parent) { + this.$parent = $(this.options.parent) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension + , scroll + , actives + , hasData + + if (this.transitioning) return + + dimension = this.dimension() + scroll = $.camelCase(['scroll', dimension].join('-')) + actives = this.$parent && this.$parent.find('> .accordion-group > .in') + + if (actives && actives.length) { + hasData = actives.data('collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', $.Event('show'), 'shown') + $.support.transition && this.$element[dimension](this.$element[0][scroll]) + } + + , hide: function () { + var dimension + if (this.transitioning) return + dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', $.Event('hide'), 'hidden') + this.$element[dimension](0) + } + + , reset: function (size) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') + + return this + } + + , transition: function (method, startEvent, completeEvent) { + var that = this + , complete = function () { + if (startEvent.type == 'show') that.reset() + that.transitioning = 0 + that.$element.trigger(completeEvent) + } + + this.$element.trigger(startEvent) + + if (startEvent.isDefaultPrevented()) return + + this.transitioning = 1 + + this.$element[method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + + /* COLLAPSE PLUGIN DEFINITION + * ========================== */ + + var old = $.fn.collapse + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSE NO CONFLICT + * ==================== */ + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + /* COLLAPSE DATA-API + * ================= */ + + $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + $(target).collapse(option) + }) + +}(window.jQuery);/* ============================================================ + * bootstrap-dropdown.js v2.2.2 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, 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. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle=dropdown]' + , Dropdown = function (element) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function (e) { + var $this = $(this) + , $parent + , isActive + + if ($this.is('.disabled, :disabled')) return + + $parent = getParent($this) + + isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + $parent.toggleClass('open') + } + + $this.focus() + + return false + } + + , keydown: function (e) { + var $this + , $items + , $active + , $parent + , isActive + , index + + if (!/(38|40|27)/.test(e.keyCode)) return + + $this = $(this) + + e.preventDefault() + e.stopPropagation() + + if ($this.is('.disabled, :disabled')) return + + $parent = getParent($this) + + isActive = $parent.hasClass('open') + + if (!isActive || (isActive && e.keyCode == 27)) return $this.click() + + $items = $('[role=menu] li:not(.divider):visible a', $parent) + + if (!$items.length) return + + index = $items.index($items.filter(':focus')) + + if (e.keyCode == 38 && index > 0) index-- // up + if (e.keyCode == 40 && index < $items.length - 1) index++ // down + if (!~index) index = 0 + + $items + .eq(index) + .focus() + } + + } + + function clearMenus() { + $(toggle).each(function () { + getParent($(this)).removeClass('open') + }) + } + + function getParent($this) { + var selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + return $parent + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + var old = $.fn.dropdown + + $.fn.dropdown = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* DROPDOWN NO CONFLICT + * ==================== */ + + $.fn.dropdown.noConflict = function () { + $.fn.dropdown = old + return this + } + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(document) + .on('click.dropdown.data-api touchstart.dropdown.data-api', clearMenus) + .on('click.dropdown touchstart.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) + .on('touchstart.dropdown.data-api', '.dropdown-menu', function (e) { e.stopPropagation() }) + .on('click.dropdown.data-api touchstart.dropdown.data-api' , toggle, Dropdown.prototype.toggle) + .on('keydown.dropdown.data-api touchstart.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown) + +}(window.jQuery);/* ========================================================= + * bootstrap-modal.js v2.2.2 + * http://twitter.github.com/bootstrap/javascript.html#modals + * ========================================================= + * Copyright 2012 Twitter, 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. + * ========================================================= */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* MODAL CLASS DEFINITION + * ====================== */ + + var Modal = function (element, options) { + this.options = options + this.$element = $(element) + .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) + this.options.remote && this.$element.find('.modal-body').load(this.options.remote) + } + + Modal.prototype = { + + constructor: Modal + + , toggle: function () { + return this[!this.isShown ? 'show' : 'hide']() + } + + , show: function () { + var that = this + , e = $.Event('show') + + this.$element.trigger(e) + + if (this.isShown || e.isDefaultPrevented()) return + + this.isShown = true + + this.escape() + + this.backdrop(function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + if (!that.$element.parent().length) { + that.$element.appendTo(document.body) //don't move modals dom position + } + + that.$element + .show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element + .addClass('in') + .attr('aria-hidden', false) + + that.enforceFocus() + + transition ? + that.$element.one($.support.transition.end, function () { that.$element.focus().trigger('shown') }) : + that.$element.focus().trigger('shown') + + }) + } + + , hide: function (e) { + e && e.preventDefault() + + var that = this + + e = $.Event('hide') + + this.$element.trigger(e) + + if (!this.isShown || e.isDefaultPrevented()) return + + this.isShown = false + + this.escape() + + $(document).off('focusin.modal') + + this.$element + .removeClass('in') + .attr('aria-hidden', true) + + $.support.transition && this.$element.hasClass('fade') ? + this.hideWithTransition() : + this.hideModal() + } + + , enforceFocus: function () { + var that = this + $(document).on('focusin.modal', function (e) { + if (that.$element[0] !== e.target && !that.$element.has(e.target).length) { + that.$element.focus() + } + }) + } + + , escape: function () { + var that = this + if (this.isShown && this.options.keyboard) { + this.$element.on('keyup.dismiss.modal', function ( e ) { + e.which == 27 && that.hide() + }) + } else if (!this.isShown) { + this.$element.off('keyup.dismiss.modal') + } + } + + , hideWithTransition: function () { + var that = this + , timeout = setTimeout(function () { + that.$element.off($.support.transition.end) + that.hideModal() + }, 500) + + this.$element.one($.support.transition.end, function () { + clearTimeout(timeout) + that.hideModal() + }) + } + + , hideModal: function (that) { + this.$element + .hide() + .trigger('hidden') + + this.backdrop() + } + + , removeBackdrop: function () { + this.$backdrop.remove() + this.$backdrop = null + } + + , backdrop: function (callback) { + var that = this + , animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $(' + + + \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/resources/1_2/petstore-1.2/api-docs b/modules/swagger-codegen/src/test/resources/1_2/petstore-1.2/api-docs new file mode 100644 index 00000000000..370eca562a7 --- /dev/null +++ b/modules/swagger-codegen/src/test/resources/1_2/petstore-1.2/api-docs @@ -0,0 +1,60 @@ +{ + "apiVersion": "1.0.0", + "swaggerVersion": "1.2", + "apis": [ + { + "path": "/pet", + "description": "Operations about pets" + }, + { + "path": "/user", + "description": "Operations about user" + }, + { + "path": "/store", + "description": "Operations about store" + } + ], + "authorizations": { + "oauth2": { + "type": "oauth2", + "scopes": [ + { + "scope": "email", + "description": "Access to your email address" + }, + { + "scope": "pets", + "description": "Access to your pets" + } + ], + "grantTypes": { + "implicit": { + "loginEndpoint": { + "url": "http://petstore.swagger.wordnik.com/oauth/dialog" + }, + "tokenName": "access_token" + }, + "authorization_code": { + "tokenRequestEndpoint": { + "url": "http://petstore.swagger.wordnik.com/oauth/requestToken", + "clientIdName": "client_id", + "clientSecretName": "client_secret" + }, + "tokenEndpoint": { + "url": "http://petstore.swagger.wordnik.com/oauth/token", + "tokenName": "access_code" + } + } + } + } + }, + "info": { + "title": "Swagger Sample App", + "description": "This is a sample server Petstore server. You can find out more about Swagger \n at http://swagger.wordnik.com or on irc.freenode.net, #swagger. For this sample,\n you can use the api key \"special-key\" to test the authorization filters", + "termsOfServiceUrl": "http://helloreverb.com/terms/", + "contact": "apiteam@wordnik.com", + "license": "Apache 2.0", + "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.html" + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/resources/1_2/petstore-1.2/pet b/modules/swagger-codegen/src/test/resources/1_2/petstore-1.2/pet new file mode 100644 index 00000000000..4a8439a4424 --- /dev/null +++ b/modules/swagger-codegen/src/test/resources/1_2/petstore-1.2/pet @@ -0,0 +1,425 @@ +{ + "apiVersion": "1.0.0", + "swaggerVersion": "1.2", + "basePath": "http://petstore.swagger.wordnik.com/api", + "resourcePath": "/pet", + "produces": [ + "application/json", + "application/xml", + "text/plain", + "text/html" + ], + "apis": [ + { + "path": "/pet/{petId}", + "operations": [ + { + "method": "GET", + "summary": "Find pet by ID", + "notes": "Returns a pet based on ID", + "type": "Pet", + "nickname": "getPetById", + "authorizations": {}, + "parameters": [ + { + "name": "petId", + "description": "ID of pet that needs to be fetched", + "required": true, + "type": "integer", + "format": "int64", + "paramType": "path", + "minimum": "1.0", + "maximum": "100000.0" + } + ], + "responseMessages": [ + { + "code": 400, + "message": "Invalid ID supplied" + }, + { + "code": 404, + "message": "Pet not found" + } + ] + }, + { + "method": "PATCH", + "summary": "partial updates to a pet", + "notes": "", + "type": "array", + "items": { + "$ref": "Pet" + }, + "nickname": "partialUpdate", + "produces": [ + "application/json", + "application/xml" + ], + "consumes": [ + "application/json", + "application/xml" + ], + "authorizations": { + "oauth2": [ + { + "scope": "test:anything", + "description": "anything" + } + ] + }, + "parameters": [ + { + "name": "petId", + "description": "ID of pet that needs to be fetched", + "required": true, + "type": "string", + "paramType": "path" + }, + { + "name": "body", + "description": "Pet object that needs to be added to the store", + "required": true, + "type": "Pet", + "paramType": "body" + } + ], + "responseMessages": [ + { + "code": 400, + "message": "Invalid tag value" + } + ] + }, + { + "method": "POST", + "summary": "Updates a pet in the store with form data", + "notes": "", + "type": "void", + "nickname": "updatePetWithForm", + "consumes": [ + "application/x-www-form-urlencoded" + ], + "authorizations": { + "oauth2": [ + { + "scope": "test:anything", + "description": "anything" + } + ] + }, + "parameters": [ + { + "name": "petId", + "description": "ID of pet that needs to be updated", + "required": true, + "type": "string", + "paramType": "path" + }, + { + "name": "name", + "description": "Updated name of the pet", + "required": false, + "type": "string", + "paramType": "form" + }, + { + "name": "status", + "description": "Updated status of the pet", + "required": false, + "type": "string", + "paramType": "form" + } + ], + "responseMessages": [ + { + "code": 405, + "message": "Invalid input" + } + ] + }, + { + "method": "DELETE", + "summary": "Deletes a pet", + "notes": "", + "type": "void", + "nickname": "deletePet", + "authorizations": { + "oauth2": [ + { + "scope": "test:anything", + "description": "anything" + } + ] + }, + "parameters": [ + { + "name": "petId", + "description": "Pet id to delete", + "required": true, + "type": "string", + "paramType": "path" + } + ], + "responseMessages": [ + { + "code": 400, + "message": "Invalid pet value" + } + ] + } + ] + }, + { + "path": "/pet", + "operations": [ + { + "method": "PUT", + "summary": "Update an existing pet", + "notes": "", + "type": "void", + "nickname": "updatePet", + "authorizations": {}, + "parameters": [ + { + "name": "body", + "description": "Pet object that needs to be updated in the store", + "required": true, + "type": "Pet", + "paramType": "body" + } + ], + "responseMessages": [ + { + "code": 400, + "message": "Invalid ID supplied" + }, + { + "code": 404, + "message": "Pet not found" + }, + { + "code": 405, + "message": "Validation exception" + } + ] + }, + { + "method": "POST", + "summary": "Add a new pet to the store", + "notes": "", + "type": "void", + "nickname": "addPet", + "consumes": [ + "application/json", + "application/xml" + ], + "authorizations": { + "oauth2": [ + { + "scope": "test:anything", + "description": "anything" + } + ] + }, + "parameters": [ + { + "name": "body", + "description": "Pet object that needs to be added to the store", + "required": true, + "type": "Pet", + "paramType": "body" + } + ], + "responseMessages": [ + { + "code": 405, + "message": "Invalid input" + } + ] + } + ] + }, + { + "path": "/pet/findByStatus", + "operations": [ + { + "method": "GET", + "summary": "Finds Pets by status", + "notes": "Multiple status values can be provided with comma seperated strings", + "type": "array", + "items": { + "$ref": "Pet" + }, + "nickname": "findPetsByStatus", + "authorizations": {}, + "parameters": [ + { + "name": "status", + "description": "Status values that need to be considered for filter", + "defaultValue": "available", + "required": true, + "type": "string", + "paramType": "query", + "enum": [ + "available", + "pending", + "sold" + ] + } + ], + "responseMessages": [ + { + "code": 400, + "message": "Invalid status value" + } + ] + } + ] + }, + { + "path": "/pet/findByTags", + "operations": [ + { + "method": "GET", + "summary": "Finds Pets by tags", + "notes": "Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing.", + "type": "array", + "items": { + "$ref": "Pet" + }, + "nickname": "findPetsByTags", + "authorizations": {}, + "parameters": [ + { + "name": "tags", + "description": "Tags to filter by", + "required": true, + "type": "string", + "paramType": "query" + } + ], + "responseMessages": [ + { + "code": 400, + "message": "Invalid tag value" + } + ], + "deprecated": "true" + } + ] + }, + { + "path": "/pet/uploadImage", + "operations": [ + { + "method": "POST", + "summary": "uploads an image", + "notes": "", + "type": "void", + "nickname": "uploadFile", + "consumes": [ + "multipart/form-data" + ], + "authorizations": { + "oauth2": [ + { + "scope": "test:anything", + "description": "anything" + }, + { + "scope": "test:nothing", + "description": "nothing" + } + ] + }, + "parameters": [ + { + "name": "additionalMetadata", + "description": "Additional data to pass to server", + "required": false, + "type": "string", + "paramType": "form" + }, + { + "name": "file", + "description": "file to upload", + "required": false, + "type": "File", + "paramType": "body" + } + ] + } + ] + } + ], + "models": { + "Tag": { + "id": "Tag", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + } + } + }, + "Pet": { + "id": "Pet", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64", + "description": "unique identifier for the pet", + "minimum": "0.0", + "maximum": "100.0" + }, + "category": { + "$ref": "Category" + }, + "name": { + "type": "string" + }, + "photoUrls": { + "type": "array", + "items": { + "type": "string" + } + }, + "tags": { + "type": "array", + "items": { + "$ref": "Tag" + } + }, + "status": { + "type": "string", + "description": "pet status in the store", + "enum": [ + "available", + "pending", + "sold" + ] + } + } + }, + "Category": { + "id": "Category", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/resources/1_2/petstore-1.2/store b/modules/swagger-codegen/src/test/resources/1_2/petstore-1.2/store new file mode 100644 index 00000000000..e59994447cd --- /dev/null +++ b/modules/swagger-codegen/src/test/resources/1_2/petstore-1.2/store @@ -0,0 +1,145 @@ +{ + "apiVersion": "1.0.0", + "swaggerVersion": "1.2", + "basePath": "http://petstore.swagger.wordnik.com/api", + "resourcePath": "/store", + "produces": [ + "application/json" + ], + "apis": [ + { + "path": "/store/order/{orderId}", + "operations": [ + { + "method": "GET", + "summary": "Find purchase order by ID", + "notes": "For valid response try integer IDs with value <= 5. Anything above 5 or nonintegers will generate API errors", + "type": "Order", + "nickname": "getOrderById", + "authorizations": {}, + "parameters": [ + { + "name": "orderId", + "description": "ID of pet that needs to be fetched", + "required": true, + "type": "string", + "paramType": "path" + } + ], + "responseMessages": [ + { + "code": 400, + "message": "Invalid ID supplied" + }, + { + "code": 404, + "message": "Order not found" + } + ] + }, + { + "method": "DELETE", + "summary": "Delete purchase order by ID", + "notes": "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors", + "type": "void", + "nickname": "deleteOrder", + "authorizations": { + "oauth2": [ + { + "scope": "test:anything", + "description": "anything" + } + ] + }, + "parameters": [ + { + "name": "orderId", + "description": "ID of the order that needs to be deleted", + "required": true, + "type": "string", + "paramType": "path" + } + ], + "responseMessages": [ + { + "code": 400, + "message": "Invalid ID supplied" + }, + { + "code": 404, + "message": "Order not found" + } + ] + } + ] + }, + { + "path": "/store/order", + "operations": [ + { + "method": "POST", + "summary": "Place an order for a pet", + "notes": "", + "type": "void", + "nickname": "placeOrder", + "authorizations": { + "oauth2": [ + { + "scope": "test:anything", + "description": "anything" + } + ] + }, + "parameters": [ + { + "name": "body", + "description": "order placed for purchasing the pet", + "required": true, + "type": "Order", + "paramType": "body" + } + ], + "responseMessages": [ + { + "code": 400, + "message": "Invalid order" + } + ] + } + ] + } + ], + "models": { + "Order": { + "id": "Order", + "description": "an order in the system", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "petId": { + "type": "integer", + "format": "int64" + }, + "quantity": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": "string", + "description": "Order Status", + "enum": [ + "placed", + " approved", + " delivered" + ] + }, + "shipDate": { + "type": "string", + "format": "date-time" + } + } + } + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/resources/1_2/petstore-1.2/user b/modules/swagger-codegen/src/test/resources/1_2/petstore-1.2/user new file mode 100644 index 00000000000..c9eb3f6ff78 --- /dev/null +++ b/modules/swagger-codegen/src/test/resources/1_2/petstore-1.2/user @@ -0,0 +1,299 @@ +{ + "apiVersion": "1.0.0", + "swaggerVersion": "1.2", + "basePath": "http://petstore.swagger.wordnik.com/api", + "resourcePath": "/user", + "produces": [ + "application/json" + ], + "apis": [ + { + "path": "/user", + "operations": [ + { + "method": "POST", + "summary": "Create user", + "notes": "This can only be done by the logged in user.", + "type": "void", + "nickname": "createUser", + "authorizations": { + "oauth2": [ + { + "scope": "test:anything", + "description": "anything" + } + ] + }, + "parameters": [ + { + "name": "body", + "description": "Created user object", + "required": true, + "type": "User", + "paramType": "body" + } + ] + } + ] + }, + { + "path": "/user/logout", + "operations": [ + { + "method": "GET", + "summary": "Logs out current logged in user session", + "notes": "", + "type": "void", + "nickname": "logoutUser", + "authorizations": {}, + "parameters": [] + } + ] + }, + { + "path": "/user/createWithArray", + "operations": [ + { + "method": "POST", + "summary": "Creates list of users with given input array", + "notes": "", + "type": "void", + "nickname": "createUsersWithArrayInput", + "authorizations": { + "oauth2": [ + { + "scope": "test:anything", + "description": "anything" + } + ] + }, + "parameters": [ + { + "name": "body", + "description": "List of user object", + "required": true, + "type": "array", + "items": { + "$ref": "User" + }, + "paramType": "body" + } + ] + } + ] + }, + { + "path": "/user/createWithList", + "operations": [ + { + "method": "POST", + "summary": "Creates list of users with given list input", + "notes": "", + "type": "void", + "nickname": "createUsersWithListInput", + "authorizations": { + "oauth2": [ + { + "scope": "test:anything", + "description": "anything" + } + ] + }, + "parameters": [ + { + "name": "body", + "description": "List of user object", + "required": true, + "type": "array", + "items": { + "$ref": "User" + }, + "paramType": "body" + } + ] + } + ] + }, + { + "path": "/user/{username}", + "operations": [ + { + "method": "PUT", + "summary": "Updated user", + "notes": "This can only be done by the logged in user.", + "type": "void", + "nickname": "updateUser", + "authorizations": { + "oauth2": [ + { + "scope": "test:anything", + "description": "anything" + } + ] + }, + "parameters": [ + { + "name": "username", + "description": "name that need to be deleted", + "required": true, + "type": "string", + "paramType": "path" + }, + { + "name": "body", + "description": "Updated user object", + "required": true, + "type": "User", + "paramType": "body" + } + ], + "responseMessages": [ + { + "code": 400, + "message": "Invalid username supplied" + }, + { + "code": 404, + "message": "User not found" + } + ] + }, + { + "method": "DELETE", + "summary": "Delete user", + "notes": "This can only be done by the logged in user.", + "type": "void", + "nickname": "deleteUser", + "authorizations": { + "oauth2": [ + { + "scope": "test:anything", + "description": "anything" + } + ] + }, + "parameters": [ + { + "name": "username", + "description": "The name that needs to be deleted", + "required": true, + "type": "string", + "paramType": "path" + } + ], + "responseMessages": [ + { + "code": 400, + "message": "Invalid username supplied" + }, + { + "code": 404, + "message": "User not found" + } + ] + }, + { + "method": "GET", + "summary": "Get user by user name", + "notes": "", + "type": "User", + "nickname": "getUserByName", + "authorizations": {}, + "parameters": [ + { + "name": "username", + "description": "The name that needs to be fetched. Use user1 for testing.", + "required": true, + "type": "string", + "paramType": "path" + } + ], + "responseMessages": [ + { + "code": 400, + "message": "Invalid username supplied" + }, + { + "code": 404, + "message": "User not found" + } + ] + } + ] + }, + { + "path": "/user/login", + "operations": [ + { + "method": "GET", + "summary": "Logs user into the system", + "notes": "", + "type": "string", + "nickname": "loginUser", + "authorizations": {}, + "parameters": [ + { + "name": "username", + "description": "The user name for login", + "required": true, + "type": "string", + "paramType": "query" + }, + { + "name": "password", + "description": "The password for login in clear text", + "required": true, + "type": "string", + "paramType": "query" + } + ], + "responseMessages": [ + { + "code": 400, + "message": "Invalid username and password combination" + } + ] + } + ] + } + ], + "models": { + "User": { + "id": "User", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "firstName": { + "type": "string" + }, + "username": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "password": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "userStatus": { + "type": "integer", + "format": "int32", + "description": "User Status", + "enum": [ + "1-registered", + "2-active", + "3-closed" + ] + } + } + } + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/resources/2_0/petstore.json b/modules/swagger-codegen/src/test/resources/2_0/petstore.json new file mode 100644 index 00000000000..daa8ef91b15 --- /dev/null +++ b/modules/swagger-codegen/src/test/resources/2_0/petstore.json @@ -0,0 +1,951 @@ +{ + "swagger": "2.0", + "info": { + "description": "This is a sample server Petstore server. You can find out more about Swagger at http://swagger.wordnik.com or on irc.freenode.net, #swagger. For this sample, you can use the api key \"special-key\" to test the authorization filters", + "version": "1.0.0", + "title": "Swagger Petstore", + "termsOfService": "http://helloreverb.com/terms/", + "contact": { + "name": "apiteam@wordnik.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "petstore.swagger.wordnik.com", + "basePath": "/v2", + "schemes": [ + "http" + ], + "paths": { + "/pet": { + "post": { + "tags": [ + "pet" + ], + "summary": "Add a new pet to the store", + "description": "", + "operationId": "addPet", + "consumes": [ + "application/json", + "application/xml" + ], + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "body", + "name": "pet", + "description": "Pet object that needs to be added to the store", + "required": false, + "schema": { + "$ref": "#/definitions/Pet" + } + } + ], + "responses": { + "405": { + "description": "Invalid input" + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + }, + "put": { + "tags": [ + "pet" + ], + "summary": "Update an existing pet", + "description": "", + "operationId": "updatePet", + "consumes": [ + "application/json", + "application/xml" + ], + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Pet object that needs to be added to the store", + "required": false, + "schema": { + "$ref": "#/definitions/Pet" + } + } + ], + "responses": { + "405": { + "description": "Validation exception" + }, + "404": { + "description": "Pet not found" + }, + "400": { + "description": "Invalid ID supplied" + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + } + }, + "/pet/findByStatus": { + "get": { + "tags": [ + "pet" + ], + "summary": "Finds Pets by status", + "description": "Multiple status values can be provided with comma seperated strings", + "operationId": "findPetsByStatus", + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "query", + "name": "status", + "description": "Status values that need to be considered for filter", + "required": false, + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Pet" + } + } + }, + "400": { + "description": "Invalid status value" + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + } + }, + "/pet/findByTags": { + "get": { + "tags": [ + "pet" + ], + "summary": "Finds Pets by tags", + "description": "Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing.", + "operationId": "findPetsByTags", + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "query", + "name": "tags", + "description": "Tags to filter by", + "required": false, + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Pet" + } + } + }, + "400": { + "description": "Invalid tag value" + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + } + }, + "/pet/{petId}/upload": { + "post": { + "tags": [ "pet" ], + "summary": "Upload an image for a pet", + "operationId": "uploadImage", + "consumes": [ + "multipart/form-data" + ], + "parameters": [ + { + "in": "formData", + "name": "petImage", + "description": "image to upload", + "type": "file" + } + ], + "responses": { + "default": { + "description": "it worked" + } + } + } + }, + "/pet/{petId}": { + "get": { + "tags": [ + "pet" + ], + "summary": "Find pet by ID", + "description": "Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions", + "operationId": "getPetById", + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "path", + "name": "petId", + "description": "ID of pet that needs to be fetched", + "required": true, + "type": "integer", + "format": "int64" + } + ], + "responses": { + "404": { + "description": "Pet not found" + }, + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/Pet" + } + }, + "400": { + "description": "Invalid ID supplied" + } + }, + "security": [ + { + "api_key": [] + }, + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + }, + "post": { + "tags": [ + "pet" + ], + "summary": "Updates a pet in the store with form data", + "description": "", + "operationId": "updatePetWithForm", + "consumes": [ + "application/x-www-form-urlencoded" + ], + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "path", + "name": "petId", + "description": "ID of pet that needs to be updated", + "required": true, + "type": "string" + }, + { + "in": "formData", + "name": "name", + "description": "Updated name of the pet", + "required": true, + "type": "string" + }, + { + "in": "formData", + "name": "status", + "description": "Updated status of the pet", + "required": true, + "type": "string" + } + ], + "responses": { + "405": { + "description": "Invalid input" + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + }, + "delete": { + "tags": [ + "pet" + ], + "summary": "Deletes a pet", + "description": "", + "operationId": "deletePet", + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "header", + "name": "api_key", + "description": "", + "required": true, + "type": "string" + }, + { + "in": "path", + "name": "petId", + "description": "Pet id to delete", + "required": true, + "type": "integer", + "format": "int64" + } + ], + "responses": { + "400": { + "description": "Invalid pet value" + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + } + }, + "/store/order": { + "post": { + "tags": [ + "store" + ], + "summary": "Place an order for a pet", + "description": "", + "operationId": "placeOrder", + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "body", + "name": "body", + "description": "order placed for purchasing the pet", + "required": false, + "schema": { + "$ref": "#/definitions/Order" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/Order" + } + }, + "400": { + "description": "Invalid Order" + } + } + } + }, + "/store/order/{orderId}": { + "get": { + "tags": [ + "store" + ], + "summary": "Find purchase order by ID", + "description": "For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions", + "operationId": "getOrderById", + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "path", + "name": "orderId", + "description": "ID of pet that needs to be fetched", + "required": true, + "type": "string" + } + ], + "responses": { + "404": { + "description": "Order not found" + }, + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/Order" + } + }, + "400": { + "description": "Invalid ID supplied" + } + } + }, + "delete": { + "tags": [ + "store" + ], + "summary": "Delete purchase order by ID", + "description": "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors", + "operationId": "deleteOrder", + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "path", + "name": "orderId", + "description": "ID of the order that needs to be deleted", + "required": true, + "type": "string" + } + ], + "responses": { + "404": { + "description": "Order not found" + }, + "400": { + "description": "Invalid ID supplied" + } + } + } + }, + "/user": { + "post": { + "tags": [ + "user" + ], + "summary": "Create user", + "description": "This can only be done by the logged in user.", + "operationId": "createUser", + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Created user object", + "required": false, + "schema": { + "$ref": "#/definitions/User" + } + } + ], + "responses": { + "default": { + "description": "successful operation" + } + } + } + }, + "/user/createWithArray": { + "post": { + "tags": [ + "user" + ], + "summary": "Creates list of users with given input array", + "description": "", + "operationId": "createUsersWithArrayInput", + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "body", + "name": "body", + "description": "List of user object", + "required": false, + "schema": { + "type": "array", + "items": { + "$ref": "User" + } + } + } + ], + "responses": { + "default": { + "description": "successful operation" + } + } + } + }, + "/user/createWithList": { + "post": { + "tags": [ + "user" + ], + "summary": "Creates list of users with given input array", + "description": "", + "operationId": "createUsersWithListInput", + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "body", + "name": "body", + "description": "List of user object", + "required": false, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/User" + } + } + } + ], + "responses": { + "default": { + "description": "successful operation" + } + } + } + }, + "/user/login": { + "get": { + "tags": [ + "user" + ], + "summary": "Logs user into the system", + "description": "", + "operationId": "loginUser", + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "query", + "name": "username", + "description": "The user name for login", + "required": false, + "type": "string" + }, + { + "in": "query", + "name": "password", + "description": "The password for login in clear text", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Invalid username/password supplied" + } + } + } + }, + "/user/logout": { + "get": { + "tags": [ + "user" + ], + "summary": "Logs out current logged in user session", + "description": "", + "operationId": "logoutUser", + "produces": [ + "application/json", + "application/xml" + ], + "responses": { + "default": { + "description": "successful operation" + } + } + } + }, + "/user/{username}": { + "get": { + "tags": [ + "user" + ], + "summary": "Get user by user name", + "description": "", + "operationId": "getUserByName", + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "path", + "name": "username", + "description": "The name that needs to be fetched. Use user1 for testing. ", + "required": true, + "type": "string" + } + ], + "responses": { + "404": { + "description": "User not found" + }, + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/User" + } + }, + "400": { + "description": "Invalid username supplied" + } + } + }, + "put": { + "tags": [ + "user" + ], + "summary": "Updated user", + "description": "This can only be done by the logged in user.", + "operationId": "updateUser", + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "path", + "name": "username", + "description": "name that need to be deleted", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "description": "Updated user object", + "required": false, + "schema": { + "$ref": "#/definitions/User" + } + } + ], + "responses": { + "404": { + "description": "User not found" + }, + "400": { + "description": "Invalid user supplied" + } + } + }, + "delete": { + "tags": [ + "user" + ], + "summary": "Delete user", + "description": "This can only be done by the logged in user.", + "operationId": "deleteUser", + "produces": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "path", + "name": "username", + "description": "The name that needs to be deleted", + "required": true, + "type": "string" + } + ], + "responses": { + "404": { + "description": "User not found" + }, + "400": { + "description": "Invalid username supplied" + } + } + } + } + }, + "securityDefinitions": { + "api_key": { + "type": "apiKey", + "name": "api_key", + "in": "header" + }, + "petstore_auth": { + "type": "oauth2", + "authorizationUrl": "http://petstore.swagger.wordnik.com/api/oauth/dialog", + "flow": "implicit" + } + }, + "definitions": { + "User": { + "properties": { + "id": { + "type": "integer", + "format": "int64", + "xml": { + "name": "id" + } + }, + "username": { + "type": "string", + "xml": { + "name": "username" + } + }, + "firstName": { + "type": "string", + "xml": { + "name": "firstName" + } + }, + "lastName": { + "type": "string", + "xml": { + "name": "lastName" + } + }, + "email": { + "type": "string", + "xml": { + "name": "email" + } + }, + "password": { + "type": "string", + "xml": { + "name": "password" + } + }, + "phone": { + "type": "string", + "xml": { + "name": "phone" + } + }, + "userStatus": { + "type": "integer", + "format": "int32", + "xml": { + "name": "userStatus" + }, + "description": "User Status" + } + }, + "xml": { + "name": "User" + } + }, + "Category": { + "properties": { + "id": { + "type": "integer", + "format": "int64", + "xml": { + "name": "id" + } + }, + "name": { + "type": "string", + "xml": { + "name": "name" + } + } + }, + "xml": { + "name": "Category" + } + }, + "Pet": { + "required": [ + "name", + "photoUrls" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64", + "xml": { + "name": "id" + } + }, + "category": { + "xml": { + "name": "category" + }, + "$ref": "Category" + }, + "name": { + "type": "string", + "example": "doggie", + "xml": { + "name": "name" + } + }, + "photoUrls": { + "type": "array", + "xml": { + "name": "photoUrl", + "wrapped": true + }, + "items": { + "type": "string" + } + }, + "tags": { + "type": "array", + "xml": { + "name": "tag", + "wrapped": true + }, + "items": { + "$ref": "Tag" + } + }, + "status": { + "type": "string", + "xml": { + "name": "status" + }, + "description": "pet status in the store" + } + }, + "xml": { + "name": "Pet" + } + }, + "Tag": { + "properties": { + "id": { + "type": "integer", + "format": "int64", + "xml": { + "name": "id" + } + }, + "name": { + "type": "string", + "xml": { + "name": "name" + } + } + }, + "xml": { + "name": "Tag" + } + }, + "Order": { + "properties": { + "id": { + "type": "integer", + "format": "int64", + "xml": { + "name": "id" + } + }, + "petId": { + "type": "integer", + "format": "int64", + "xml": { + "name": "petId" + } + }, + "quantity": { + "type": "integer", + "format": "int32", + "xml": { + "name": "quantity" + } + }, + "shipDate": { + "type": "string", + "format": "date-time", + "xml": { + "name": "shipDate" + } + }, + "status": { + "type": "string", + "xml": { + "name": "status" + }, + "description": "Order Status" + }, + "complete": { + "type": "boolean" + } + }, + "xml": { + "name": "Order" + } + } + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/resources/2_0/postBodyTest.json b/modules/swagger-codegen/src/test/resources/2_0/postBodyTest.json new file mode 100644 index 00000000000..ed13a5820eb --- /dev/null +++ b/modules/swagger-codegen/src/test/resources/2_0/postBodyTest.json @@ -0,0 +1,102 @@ +{ + "swagger": "2.0", + "info": { + "description": "This is a sample server Petstore server. You can find out more about Swagger at http://swagger.wordnik.com or on irc.freenode.net, #swagger. For this sample, you can use the api key \"special-key\" to test the authorization filters", + "version": "1.0.0", + "title": "Swagger Petstore", + "termsOfService": "http://helloreverb.com/terms/", + "contact": { + "name": "apiteam@wordnik.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "petstore.swagger.wordnik.com", + "basePath": "/v2", + "schemes": [ + "http" + ], + "paths": { + "/animals": { + "post": { + "tags": [ + "pet" + ], + "summary": "Add a new animal to the store", + "description": "", + "consumes": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "body", + "name": "pet", + "description": "Animals", + "required": false, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Animal" + } + } + } + ], + "responses": { + "405": { + "description": "Invalid input" + } + } + } + }, + "/insects": { + "post": { + "tags": [ + "pet" + ], + "summary": "Add a new insect to the store", + "description": "", + "consumes": [ + "application/json", + "application/xml" + ], + "parameters": [ + { + "in": "body", + "name": "pet", + "description": "Insects", + "required": false, + "schema": { + "$ref": "#/definitions/Insect" + } + } + ], + "responses": { + "405": { + "description": "Invalid input" + } + } + } + } + }, + "definitions": { + "Animal": { + "properties": { + "id": { + "type": "integer", + "format": "int64" + } + } + }, + "Insect": { + "properties": { + "id": { + "type": "integer", + "format": "int64" + } + } + } + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/scala/CodegenTest.scala b/modules/swagger-codegen/src/test/scala/CodegenTest.scala new file mode 100644 index 00000000000..ecd586a6a89 --- /dev/null +++ b/modules/swagger-codegen/src/test/scala/CodegenTest.scala @@ -0,0 +1,98 @@ +import com.wordnik.swagger.models._ +import com.wordnik.swagger.util.Json +import io.swagger.parser._ + +import com.wordnik.swagger.codegen.DefaultCodegen + +import org.junit.runner.RunWith +import org.scalatest.junit.JUnitRunner +import org.scalatest.FlatSpec +import org.scalatest.Matchers + +import scala.collection.JavaConverters._ + +@RunWith(classOf[JUnitRunner]) +class CodegenTest extends FlatSpec with Matchers { + behavior of "Codegen" + + it should "read a file upload param from a 2.0 spec" in { + val model = new SwaggerParser() + .read("src/test/resources/2_0/petstore.json") + + val codegen = new DefaultCodegen() + val path = "/pet/{petId}/upload" + val p = model.getPaths().get(path).getPost() + val op = codegen.fromOperation(path, "post", p) + + op.operationId should be ("uploadImage") + op.httpMethod should be ("POST") + op.hasConsumes should equal (true) + op.consumes.size should be(1) + op.consumes.get(0).get("mediaType") should be ("multipart/form-data") + + op.hasProduces should be (null) + + val allParams = op.allParams + allParams.size should be (1) + + val formParams = op.formParams + formParams.size should be (1) + + val file = formParams.get(0) + file.isFormParam should equal (true) + file.dataType should be ("file") + file.required should equal (false) + file.isFile should equal (true) + file.hasMore should be (null) + } + + it should "read formParam values from a 2.0 spec" in { + val model = new SwaggerParser() + .read("src/test/resources/2_0/petstore.json") + + val codegen = new DefaultCodegen() + val path = "/pet/{petId}" + val p = model.getPaths().get(path).getPost() + val op = codegen.fromOperation(path, "post", p) + + op.operationId should be ("updatePetWithForm") + op.httpMethod should be ("POST") + op.hasConsumes should equal (true) + op.consumes.size should be(1) + op.consumes.get(0).get("mediaType") should be ("application/x-www-form-urlencoded") + + op.hasProduces should equal (true) + op.produces.size should be(2) + op.produces.get(0).get("mediaType") should be ("application/json") + op.produces.get(0).get("hasMore") should be ("true") + op.produces.get(1).get("mediaType") should be ("application/xml") + + val pathParams = op.pathParams + pathParams.size should be (1) + + val idParam = pathParams.get(0) + idParam.isPathParam should equal (true) + idParam.dataType should be ("String") + idParam.required should equal (true) + idParam.hasMore should be (null) + + val allParams = op.allParams + allParams.size should be (3) + + val formParams = op.formParams + formParams.size should be (2) + val nameParam = formParams.get(0) + nameParam.isFormParam should equal (true) + nameParam.notFile should equal (true) + nameParam.dataType should be ("String") + nameParam.required should equal (true) + nameParam.hasMore should equal (true) + + val statusParam = formParams.get(1) + statusParam.isFormParam should equal (true) + statusParam.notFile should equal (true) + statusParam.dataType should be ("String") + statusParam.required should equal (true) + statusParam.hasMore should be (null) + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/scala/Java/JavaModelEnumTest.scala b/modules/swagger-codegen/src/test/scala/Java/JavaModelEnumTest.scala new file mode 100644 index 00000000000..25232b69907 --- /dev/null +++ b/modules/swagger-codegen/src/test/scala/Java/JavaModelEnumTest.scala @@ -0,0 +1,33 @@ +package Java + +import com.wordnik.swagger.codegen.languages.JavaClientCodegen +import com.wordnik.swagger.models._ +import com.wordnik.swagger.models.properties._ +import org.junit.runner.RunWith +import org.scalatest.{FlatSpec, Matchers} +import org.scalatest.junit.JUnitRunner + +import scala.collection.JavaConverters._ + +@RunWith(classOf[JUnitRunner]) +class JavaModelEnumTest extends FlatSpec with Matchers { + + it should "convert a java model with an enum" in { + val enumProperty = new StringProperty() + enumProperty.setEnum(List("VALUE1", "VALUE2", "VALUE3").asJava) + val model = new ModelImpl() + .property("name", enumProperty) + + val codegen = new JavaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.vars.size should be(1) + val enumVar = cm.vars.get(0) + enumVar.baseName should be("name") + enumVar.datatype should be("NameEnum") + enumVar.name should be("name") + enumVar.defaultValue should be("null") + enumVar.baseType should be("String") + enumVar.isEnum should equal(true) + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/scala/Java/JavaModelTest.scala b/modules/swagger-codegen/src/test/scala/Java/JavaModelTest.scala new file mode 100644 index 00000000000..513786e4609 --- /dev/null +++ b/modules/swagger-codegen/src/test/scala/Java/JavaModelTest.scala @@ -0,0 +1,268 @@ +package Java + +import com.wordnik.swagger.codegen.languages.JavaClientCodegen +import com.wordnik.swagger.util.Json +import com.wordnik.swagger.models._ +import com.wordnik.swagger.models.properties._ + +import org.junit.runner.RunWith +import org.scalatest.junit.JUnitRunner +import org.scalatest.FlatSpec +import org.scalatest.Matchers + +import scala.collection.JavaConverters._ + +@RunWith(classOf[JUnitRunner]) +class JavaModelTest extends FlatSpec with Matchers { + + it should "convert a simple java model" in { + val model = new ModelImpl() + .description("a sample model") + .property("id", new LongProperty()) + .property("name", new StringProperty()) + .property("createdAt", new DateTimeProperty()) + .required("id") + .required("name") + + val codegen = new JavaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (3) + + val vars = cm.vars + vars.get(0).baseName should be ("id") + vars.get(0).getter should be ("getId") + vars.get(0).setter should be ("setId") + vars.get(0).datatype should be ("Long") + vars.get(0).name should be ("id") + vars.get(0).defaultValue should be ("null") + vars.get(0).baseType should be ("Long") + vars.get(0).hasMore should equal (true) + vars.get(0).required should equal (true) + vars.get(0).isNotContainer should equal (true) + + vars.get(1).baseName should be ("name") + vars.get(1).getter should be ("getName") + vars.get(1).setter should be ("setName") + vars.get(1).datatype should be ("String") + vars.get(1).name should be ("name") + vars.get(1).defaultValue should be ("null") + vars.get(1).baseType should be ("String") + vars.get(1).hasMore should equal (true) + vars.get(1).required should equal (true) + vars.get(1).isNotContainer should equal (true) + + vars.get(2).baseName should be ("createdAt") + vars.get(2).getter should be ("getCreatedAt") + vars.get(2).setter should be ("setCreatedAt") + vars.get(2).datatype should be ("Date") + vars.get(2).name should be ("createdAt") + vars.get(2).defaultValue should be ("null") + vars.get(2).baseType should be ("Date") + vars.get(2).hasMore should equal (null) + vars.get(2).required should equal (false) + vars.get(2).isNotContainer should equal (true) + } + + it should "convert a model with list property" in { + val model = new ModelImpl() + .description("a sample model") + .property("id", new LongProperty()) + .property("urls", new ArrayProperty() + .items(new StringProperty())) + .required("id") + + val codegen = new JavaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (2) + + val vars = cm.vars + vars.get(1).baseName should be ("urls") + vars.get(1).getter should be ("getUrls") + vars.get(1).setter should be ("setUrls") + vars.get(1).datatype should be ("List") + vars.get(1).name should be ("urls") + vars.get(1).defaultValue should be ("new ArrayList() ") + vars.get(1).baseType should be ("List") + vars.get(1).containerType should be ("array") + vars.get(1).required should equal (false) + vars.get(1).isContainer should equal (true) + } + + it should "convert a model with a map property" in { + val model = new ModelImpl() + .description("a sample model") + .property("translations", new MapProperty() + .additionalProperties(new StringProperty())) + .required("id") + + val codegen = new JavaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (1) + + val vars = cm.vars + vars.get(0).baseName should be ("translations") + vars.get(0).getter should be ("getTranslations") + vars.get(0).setter should be ("setTranslations") + vars.get(0).datatype should be ("Map") + vars.get(0).name should be ("translations") + vars.get(0).defaultValue should be ("new HashMap() ") + vars.get(0).baseType should be ("Map") + vars.get(0).containerType should be ("map") + vars.get(0).required should equal (false) + vars.get(0).isContainer should equal (true) + } + + it should "convert a model with complex properties" in { + val model = new ModelImpl() + .description("a sample model") + .property("children", new RefProperty("#/definitions/Children")) + + val codegen = new JavaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (1) + + val vars = cm.vars + vars.get(0).baseName should be ("children") + vars.get(0).getter should be ("getChildren") + vars.get(0).setter should be ("setChildren") + vars.get(0).datatype should be ("Children") + vars.get(0).name should be ("children") + vars.get(0).defaultValue should be ("null") + vars.get(0).baseType should be ("Children") + vars.get(0).required should equal (false) + vars.get(0).isNotContainer should equal (true) + } + + it should "convert a model with complex list property" in { + val model = new ModelImpl() + .description("a sample model") + .property("children", new ArrayProperty() + .items(new RefProperty("#/definitions/Children"))) + + val codegen = new JavaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (1) + + val vars = cm.vars + vars.get(0).baseName should be ("children") + vars.get(0).complexType should be ("Children") + vars.get(0).getter should be ("getChildren") + vars.get(0).setter should be ("setChildren") + vars.get(0).datatype should be ("List") + vars.get(0).name should be ("children") + vars.get(0).defaultValue should be ("new ArrayList() ") + vars.get(0).baseType should be ("List") + vars.get(0).containerType should be ("array") + vars.get(0).required should equal (false) + vars.get(0).isContainer should equal (true) + } + + it should "convert a model with complex map property" in { + val model = new ModelImpl() + .description("a sample model") + .property("children", new MapProperty() + .additionalProperties(new RefProperty("#/definitions/Children"))) + + val codegen = new JavaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (1) + (cm.imports.asScala.toSet & Set("Map", "List", "Children")).size should be (3) + + val vars = cm.vars + vars.get(0).baseName should be ("children") + vars.get(0).complexType should be ("Children") + vars.get(0).getter should be ("getChildren") + vars.get(0).setter should be ("setChildren") + vars.get(0).datatype should be ("Map") + vars.get(0).name should be ("children") + vars.get(0).defaultValue should be ("new HashMap() ") + vars.get(0).baseType should be ("Map") + vars.get(0).containerType should be ("map") + vars.get(0).required should equal (false) + vars.get(0).isContainer should equal (true) + vars.get(0).isNotContainer should be (null) + } + + it should "convert an array model" in { + val model = new ArrayModel() + .description("an array model") + .items(new RefProperty("#/definitions/Children")) + val codegen = new JavaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("an array model") + cm.vars.size should be (0) + cm.parent should be ("ArrayList") + cm.imports.size should be (3) + (cm.imports.asScala.toSet & Set("List", "ArrayList", "Children")).size should be (3) + } + + it should "convert an map model" in { + val model = new ModelImpl() + .description("an map model") + .additionalProperties(new RefProperty("#/definitions/Children")) + + val codegen = new JavaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("an map model") + cm.vars.size should be (0) + cm.parent should be ("HashMap") + cm.imports.size should be (3) + (cm.imports.asScala.toSet & Set("Map", "HashMap", "Children")).size should be (3) + } + + it should "convert a model with upper-case property names" in { + val model = new ModelImpl() + .description("a model with upper-case property names") + .property("NAME", new StringProperty()) + .required("NAME") + + val codegen = new JavaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.vars.size should be (1) + + val vars = cm.vars + vars.get(0).baseName should be ("NAME") + vars.get(0).getter should be ("getNAME") + vars.get(0).setter should be ("setNAME") + vars.get(0).datatype should be ("String") + vars.get(0).name should be ("NAME") + vars.get(0).defaultValue should be ("null") + vars.get(0).baseType should be ("String") + vars.get(0).hasMore should equal (null) + vars.get(0).required should equal (true) + vars.get(0).isNotContainer should equal (true) + } +} diff --git a/modules/swagger-codegen/src/test/scala/Objc/ObjcModelTest.scala b/modules/swagger-codegen/src/test/scala/Objc/ObjcModelTest.scala new file mode 100644 index 00000000000..2c8db5a1223 --- /dev/null +++ b/modules/swagger-codegen/src/test/scala/Objc/ObjcModelTest.scala @@ -0,0 +1,260 @@ +package objc + +import com.wordnik.swagger.codegen.languages.ObjcClientCodegen +import com.wordnik.swagger.util.{ Json, SwaggerLoader } +import com.wordnik.swagger.models._ +import com.wordnik.swagger.models.properties._ + +import org.junit.runner.RunWith +import org.scalatest.junit.JUnitRunner +import org.scalatest.FlatSpec +import org.scalatest.Matchers + +import scala.collection.JavaConverters._ + +@RunWith(classOf[JUnitRunner]) +class ObjcModelTest extends FlatSpec with Matchers { + + it should "convert a simple java model" in { + val model = new ModelImpl() + .description("a sample model") + .property("id", new LongProperty()) + .property("name", new StringProperty()) + .property("createdAt", new DateTimeProperty()) + .required("id") + .required("name") + + val codegen = new ObjcClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("SWGSample") + cm.description should be ("a sample model") + cm.vars.size should be (3) + + val vars = cm.vars + vars.get(0).baseName should be ("id") + vars.get(0).datatype should be ("NSNumber*") + vars.get(0).name should be ("_id") + vars.get(0).defaultValue should be (null) + vars.get(0).baseType should be ("NSNumber") + vars.get(0).hasMore should equal (true) + vars.get(0).required should equal (true) + vars.get(0).isPrimitiveType should equal (true) + vars.get(0).isNotContainer should equal (true) + + vars.get(1).baseName should be ("name") + vars.get(1).datatype should be ("NSString*") + vars.get(1).name should be ("name") + vars.get(1).defaultValue should be (null) + vars.get(1).baseType should be ("NSString") + vars.get(1).hasMore should equal (true) + vars.get(1).required should equal (true) + vars.get(0).isPrimitiveType should equal (true) + vars.get(1).isNotContainer should equal (true) + + vars.get(2).baseName should be ("createdAt") + vars.get(2).complexType should be ("SWGDate") + vars.get(2).datatype should be ("SWGDate*") + vars.get(2).name should be ("createdAt") + vars.get(2).defaultValue should be (null) + vars.get(2).baseType should be ("SWGDate") + vars.get(2).hasMore should equal (null) + vars.get(2).required should equal (false) + vars.get(2).isNotContainer should equal (true) + + (cm.imports.asScala.toSet & + Set("SWGDate")).size should be (1) + } + + it should "convert a model with list property" in { + val model = new ModelImpl() + .description("a sample model") + .property("id", new LongProperty()) + .property("urls", new ArrayProperty() + .items(new StringProperty())) + .required("id") + + val codegen = new ObjcClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("SWGSample") + cm.description should be ("a sample model") + cm.vars.size should be (2) + + val vars = cm.vars + vars.get(0).baseName should be ("id") + vars.get(0).datatype should be ("NSNumber*") + vars.get(0).name should be ("_id") + vars.get(0).defaultValue should be (null) + vars.get(0).baseType should be ("NSNumber") + vars.get(0).hasMore should equal (true) + vars.get(0).required should equal (true) + vars.get(0).isPrimitiveType should equal (true) + vars.get(0).isNotContainer should equal (true) + + vars.get(1).baseName should be ("urls") + vars.get(1).datatype should be ("NSArray*") + vars.get(1).name should be ("urls") + // vars.get(1).defaultValue should be ("null") + vars.get(1).baseType should be ("NSArray") + vars.get(1).hasMore should be (null) + vars.get(1).containerType should equal ("array") + vars.get(1).required should equal (false) + vars.get(1).isPrimitiveType should equal (true) + vars.get(1).isContainer should equal (true) + } + + it should "convert a model with a map property" in { + val model = new ModelImpl() + .description("a sample model") + .property("translations", new MapProperty() + .additionalProperties(new StringProperty())) + .required("id") + + val codegen = new ObjcClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("SWGSample") + cm.description should be ("a sample model") + cm.vars.size should be (1) + + val vars = cm.vars + vars.get(0).baseName should be ("translations") + vars.get(0).datatype should be ("NSDictionary*") + vars.get(0).name should be ("translations") + vars.get(0).baseType should be ("NSDictionary") + vars.get(0).containerType should be ("map") + vars.get(0).required should equal (false) + vars.get(0).isContainer should equal (true) + vars.get(0).isPrimitiveType should equal (true) + } + + it should "convert a model with complex property" in { + val model = new ModelImpl() + .description("a sample model") + .property("children", new RefProperty("#/definitions/Children")) + + val codegen = new ObjcClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("SWGSample") + cm.description should be ("a sample model") + cm.vars.size should be (1) + + val vars = cm.vars + vars.get(0).baseName should be ("children") + vars.get(0).datatype should be ("SWGChildren*") + vars.get(0).name should be ("children") + vars.get(0).baseType should be ("SWGChildren") + vars.get(0).required should equal (false) + vars.get(0).isNotContainer should equal (true) + } + + it should "convert a model with complex list property" in { + val model = new ModelImpl() + .description("a sample model") + .property("children", new ArrayProperty() + .items(new RefProperty("#/definitions/Children"))) + + val codegen = new ObjcClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("SWGSample") + cm.description should be ("a sample model") + cm.vars.size should be (1) + + val vars = cm.vars + vars.get(0).baseName should be ("children") + vars.get(0).complexType should be ("SWGChildren") + vars.get(0).datatype should be ("NSArray*") + vars.get(0).name should be ("children") + vars.get(0).baseType should be ("NSArray") + vars.get(0).containerType should be ("array") + vars.get(0).required should equal (false) + vars.get(0).isContainer should equal (true) + } + + it should "convert a model with complex map property" in { + val model = new ModelImpl() + .description("a sample model") + .property("children", new MapProperty() + .additionalProperties(new RefProperty("#/definitions/Children"))) + + val codegen = new ObjcClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("SWGSample") + cm.description should be ("a sample model") + cm.vars.size should be (1) + (cm.imports.asScala.toSet & Set("SWGChildren")).size should be (1) + + val vars = cm.vars + vars.get(0).baseName should be ("children") + vars.get(0).complexType should be ("SWGChildren") + vars.get(0).datatype should be ("NSDictionary*") + vars.get(0).name should be ("children") + vars.get(0).baseType should be ("NSDictionary") + vars.get(0).containerType should be ("map") + vars.get(0).required should equal (false) + vars.get(0).isContainer should equal (true) + vars.get(0).isNotContainer should be (null) + } + + it should "convert an array model" in { + val model = new ArrayModel() + .description("an array model") + .items(new RefProperty("#/definitions/Children")) + val codegen = new ObjcClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("SWGSample") + cm.description should be ("an array model") + cm.vars.size should be (0) + cm.parent should be ("NSMutableArray") + cm.imports.size should be (3) + (cm.imports.asScala.toSet & Set("SWGChildren", "NSArray", "NSMutableArray")).size should be (3) + } + + it should "convert an map model" in { + val model = new ModelImpl() + .description("an map model") + .additionalProperties(new RefProperty("#/definitions/Children")) + + val codegen = new ObjcClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("SWGSample") + cm.description should be ("an map model") + cm.vars.size should be (0) + cm.parent should be ("NSMutableDictionary") + cm.imports.size should be (3) + (cm.imports.asScala.toSet & Set("SWGChildren", "NSDictionary", "NSMutableDictionary")).size should be (3) + } + + it should "create proper imports per #316" in { + val model = new SwaggerLoader().read("src/test/resources/2_0/postBodyTest.json") + val codegen = new ObjcClientCodegen() + + val animalPaths = model.getPaths() + val animalOps = animalPaths.get("/animals") + animalOps.getPost() should not be (null) + val animalCo = codegen.fromOperation("/animals", "POST", animalOps.getPost()) + animalCo.imports.size should be (1) + animalCo.imports.contains("SWGAnimal") should equal (true) + + val insectPaths = model.getPaths() + val insectOps = insectPaths.get("/insects") + insectOps.getPost() should not be (null) + val insectCo = codegen.fromOperation("/insects", "POST", insectOps.getPost()) + insectCo.imports.size should be (1) + insectCo.imports.contains("SWGInsect") should equal (true) + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/scala/SwaggerMigratorTest.scala b/modules/swagger-codegen/src/test/scala/SwaggerMigratorTest.scala new file mode 100644 index 00000000000..8051e84e660 --- /dev/null +++ b/modules/swagger-codegen/src/test/scala/SwaggerMigratorTest.scala @@ -0,0 +1,19 @@ +import com.wordnik.swagger.models._ +import io.swagger.parser._ + +import org.junit.runner.RunWith +import org.scalatest.junit.JUnitRunner +import org.scalatest.FlatSpec +import org.scalatest.Matchers + +import scala.collection.JavaConverters._ + +@RunWith(classOf[JUnitRunner]) +class SwaggerMigratorTest extends FlatSpec with Matchers { + behavior of "SwaggerMigrator" + + it should "read a 1.2 spec" in { + val loader = new SwaggerParser() + loader.read("src/test/resources/1_2/petstore-1.2/api-docs") + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/scala/php/PhpModelTest.scala b/modules/swagger-codegen/src/test/scala/php/PhpModelTest.scala new file mode 100644 index 00000000000..5e5034e5efc --- /dev/null +++ b/modules/swagger-codegen/src/test/scala/php/PhpModelTest.scala @@ -0,0 +1,259 @@ +package php + +import com.wordnik.swagger.codegen.languages.PhpClientCodegen +import com.wordnik.swagger.util.Json +import com.wordnik.swagger.models._ +import com.wordnik.swagger.models.properties._ + +import io.swagger.parser.SwaggerParser + +import org.junit.runner.RunWith +import org.scalatest.junit.JUnitRunner +import org.scalatest.FlatSpec +import org.scalatest.Matchers + +import scala.collection.JavaConverters._ + +@RunWith(classOf[JUnitRunner]) +class PhpModelTest extends FlatSpec with Matchers { + + it should "convert a simple php model" in { + val model = new ModelImpl() + .description("a sample model") + .property("id", new LongProperty()) + .property("name", new StringProperty()) + .property("createdAt", new DateTimeProperty()) + .required("id") + .required("name") + + val codegen = new PhpClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (3) + + val vars = cm.vars + vars.get(0).baseName should be ("id") + vars.get(0).datatype should be ("int") + vars.get(0).name should be ("id") + vars.get(0).defaultValue should be ("null") + vars.get(0).baseType should be ("int") + vars.get(0).hasMore should equal (true) + vars.get(0).required should equal (true) + vars.get(0).isPrimitiveType should equal (true) + vars.get(0).isNotContainer should equal (true) + + vars.get(1).baseName should be ("name") + vars.get(1).datatype should be ("string") + vars.get(1).name should be ("name") + vars.get(1).defaultValue should be ("null") + vars.get(1).baseType should be ("string") + vars.get(1).hasMore should equal (true) + vars.get(1).required should equal (true) + vars.get(0).isPrimitiveType should equal (true) + vars.get(1).isNotContainer should equal (true) + + vars.get(2).baseName should be ("createdAt") + vars.get(2).complexType should be (null) + vars.get(2).datatype should be ("DateTime") + vars.get(2).name should be ("createdAt") + vars.get(2).defaultValue should be ("null") + vars.get(2).baseType should be ("DateTime") + vars.get(2).hasMore should equal (null) + vars.get(2).required should equal (false) + vars.get(2).isNotContainer should equal (true) + + cm.imports.size() should be (0) + } + + it should "convert a model with list property" in { + val model = new ModelImpl() + .description("a sample model") + .property("id", new LongProperty()) + .property("urls", new ArrayProperty() + .items(new StringProperty())) + .required("id") + + val codegen = new PhpClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (2) + + val vars = cm.vars + vars.get(0).baseName should be ("id") + vars.get(0).datatype should be ("int") + vars.get(0).name should be ("id") + vars.get(0).defaultValue should be ("null") + vars.get(0).baseType should be ("int") + vars.get(0).hasMore should equal (true) + vars.get(0).required should equal (true) + vars.get(0).isPrimitiveType should equal (true) + vars.get(0).isNotContainer should equal (true) + + vars.get(1).baseName should be ("urls") + vars.get(1).datatype should be ("array[string]") + vars.get(1).name should be ("urls") + vars.get(1).baseType should be ("array") + vars.get(1).hasMore should be (null) + vars.get(1).containerType should equal ("array") + vars.get(1).required should equal (false) + vars.get(1).isPrimitiveType should equal (true) + vars.get(1).isContainer should equal (true) + } + + it should "convert a model with a map property" in { + val model = new ModelImpl() + .description("a sample model") + .property("translations", new MapProperty() + .additionalProperties(new StringProperty())) + .required("id") + + val codegen = new PhpClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (1) + + val vars = cm.vars + vars.get(0).baseName should be ("translations") + vars.get(0).datatype should be ("map[string,string]") + vars.get(0).name should be ("translations") + vars.get(0).baseType should be ("map") + vars.get(0).containerType should be ("map") + vars.get(0).required should equal (false) + vars.get(0).isContainer should equal (true) + vars.get(0).isPrimitiveType should equal (true) + } + + it should "convert a model with complex property" in { + val model = new ModelImpl() + .description("a sample model") + .property("children", new RefProperty("#/definitions/Children")) + + val codegen = new PhpClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (1) + + val vars = cm.vars + vars.get(0).baseName should be ("children") + vars.get(0).datatype should be ("Children") + vars.get(0).name should be ("children") + vars.get(0).baseType should be ("Children") + vars.get(0).required should equal (false) + vars.get(0).isNotContainer should equal (true) + } + + it should "convert a model with complex list property" in { + val model = new ModelImpl() + .description("a sample model") + .property("children", new ArrayProperty() + .items(new RefProperty("#/definitions/Children"))) + + val codegen = new PhpClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (1) + + val vars = cm.vars + vars.get(0).baseName should be ("children") + vars.get(0).complexType should be ("Children") + vars.get(0).datatype should be ("array[Children]") + vars.get(0).name should be ("children") + vars.get(0).baseType should be ("array") + vars.get(0).containerType should be ("array") + vars.get(0).required should equal (false) + vars.get(0).isContainer should equal (true) + } + + it should "convert a model with complex map property" in { + val model = new ModelImpl() + .description("a sample model") + .property("children", new MapProperty() + .additionalProperties(new RefProperty("#/definitions/Children"))) + + val codegen = new PhpClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (1) + (cm.imports.asScala.toSet & Set("Children")).size should be (1) + + val vars = cm.vars + vars.get(0).baseName should be ("children") + vars.get(0).complexType should be ("Children") + vars.get(0).datatype should be ("map[string,Children]") + vars.get(0).name should be ("children") + vars.get(0).baseType should be ("map") + vars.get(0).containerType should be ("map") + vars.get(0).required should equal (false) + vars.get(0).isContainer should equal (true) + vars.get(0).isNotContainer should be (null) + } + + it should "convert an array model" in { + val model = new ArrayModel() + .description("an array model") + .items(new RefProperty("#/definitions/Children")) + val codegen = new PhpClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("an array model") + cm.vars.size should be (0) + cm.imports.size should be (1) + (cm.imports.asScala.toSet & Set("Children")).size should be (1) + } + + it should "convert an map model" in { + val model = new ModelImpl() + .description("an map model") + .additionalProperties(new RefProperty("#/definitions/Children")) + + val codegen = new PhpClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("an map model") + cm.vars.size should be (0) + cm.imports.size should be (2) + (cm.imports.asScala.toSet & Set("Children")).size should be (1) + } + + it should "create proper imports per #316" in { + val model = new SwaggerParser() + .read("src/test/resources/2_0/postBodyTest.json") + val codegen = new PhpClientCodegen() + + val animalPaths = model.getPaths() + val animalOps = animalPaths.get("/animals") + animalOps.getPost() should not be (null) + val animalCo = codegen.fromOperation("/animals", "POST", animalOps.getPost()) + animalCo.imports.size should be (1) + animalCo.imports.contains("Animal") should equal (true) + + val insectPaths = model.getPaths() + val insectOps = insectPaths.get("/insects") + insectOps.getPost() should not be (null) + val insectCo = codegen.fromOperation("/insects", "POST", insectOps.getPost()) + insectCo.imports.size should be (1) + insectCo.imports.contains("Insect") should equal (true) + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/scala/scala/ScalaModelTest.scala b/modules/swagger-codegen/src/test/scala/scala/ScalaModelTest.scala new file mode 100644 index 00000000000..0c71983b1d5 --- /dev/null +++ b/modules/swagger-codegen/src/test/scala/scala/ScalaModelTest.scala @@ -0,0 +1,241 @@ +package Java + +import com.wordnik.swagger.codegen.languages.ScalaClientCodegen +import com.wordnik.swagger.util.Json +import com.wordnik.swagger.models._ +import com.wordnik.swagger.models.properties._ + +import org.junit.runner.RunWith +import org.scalatest.junit.JUnitRunner +import org.scalatest.FlatSpec +import org.scalatest.Matchers + +import scala.collection.JavaConverters._ + +@RunWith(classOf[JUnitRunner]) +class ScalaModelTest extends FlatSpec with Matchers { + + it should "convert a simple scala model" in { + val model = new ModelImpl() + .description("a sample model") + .property("id", new LongProperty()) + .property("name", new StringProperty()) + .property("createdAt", new DateTimeProperty()) + .required("id") + .required("name") + + val codegen = new ScalaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (3) + + val vars = cm.vars + vars.get(0).baseName should be ("id") + vars.get(0).getter should be ("getId") + vars.get(0).setter should be ("setId") + vars.get(0).datatype should be ("Long") + vars.get(0).name should be ("id") + vars.get(0).defaultValue should be ("null") + vars.get(0).baseType should be ("Long") + vars.get(0).hasMore should equal (true) + vars.get(0).required should equal (true) + vars.get(0).isNotContainer should equal (true) + + vars.get(1).baseName should be ("name") + vars.get(1).getter should be ("getName") + vars.get(1).setter should be ("setName") + vars.get(1).datatype should be ("String") + vars.get(1).name should be ("name") + vars.get(1).defaultValue should be ("null") + vars.get(1).baseType should be ("String") + vars.get(1).hasMore should equal (true) + vars.get(1).required should equal (true) + vars.get(1).isNotContainer should equal (true) + + vars.get(2).baseName should be ("createdAt") + vars.get(2).getter should be ("getCreatedAt") + vars.get(2).setter should be ("setCreatedAt") + vars.get(2).datatype should be ("DateTime") + vars.get(2).name should be ("createdAt") + vars.get(2).defaultValue should be ("null") + vars.get(2).baseType should be ("DateTime") + vars.get(2).hasMore should equal (null) + vars.get(2).required should equal (false) + vars.get(2).isNotContainer should equal (true) + } + + it should "convert a model with list property" in { + val model = new ModelImpl() + .description("a sample model") + .property("id", new LongProperty()) + .property("urls", new ArrayProperty() + .items(new StringProperty())) + .required("id") + + val codegen = new ScalaClientCodegen() + val cm = codegen.fromModel("sample", model) + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (2) + + val vars = cm.vars + vars.get(1).baseName should be ("urls") + vars.get(1).getter should be ("getUrls") + vars.get(1).setter should be ("setUrls") + vars.get(1).datatype should be ("List[String]") + vars.get(1).name should be ("urls") + vars.get(1).defaultValue should be ("new ListBuffer[String]() ") + vars.get(1).baseType should be ("List") + vars.get(1).containerType should be ("array") + vars.get(1).required should equal (false) + vars.get(1).isContainer should equal (true) + } + + it should "convert a model with a map property" in { + val model = new ModelImpl() + .description("a sample model") + .property("translations", new MapProperty() + .additionalProperties(new StringProperty())) + .required("id") + + val codegen = new ScalaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (1) + + val vars = cm.vars + vars.get(0).baseName should be ("translations") + vars.get(0).getter should be ("getTranslations") + vars.get(0).setter should be ("setTranslations") + vars.get(0).datatype should be ("Map[String, String]") + vars.get(0).name should be ("translations") + vars.get(0).defaultValue should be ("new HashMap[String, String]() ") + vars.get(0).baseType should be ("Map") + vars.get(0).containerType should be ("map") + vars.get(0).required should equal (false) + vars.get(0).isContainer should equal (true) + } + + it should "convert a model with complex properties" in { + val model = new ModelImpl() + .description("a sample model") + .property("children", new RefProperty("#/definitions/Children")) + + val codegen = new ScalaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (1) + + val vars = cm.vars + vars.get(0).baseName should be ("children") + vars.get(0).getter should be ("getChildren") + vars.get(0).setter should be ("setChildren") + vars.get(0).datatype should be ("Children") + vars.get(0).name should be ("children") + vars.get(0).defaultValue should be ("null") + vars.get(0).baseType should be ("Children") + vars.get(0).required should equal (false) + vars.get(0).isNotContainer should equal (true) + } + + it should "convert a model with complex list property" in { + val model = new ModelImpl() + .description("a sample model") + .property("children", new ArrayProperty() + .items(new RefProperty("#/definitions/Children"))) + + val codegen = new ScalaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (1) + + val vars = cm.vars + vars.get(0).baseName should be ("children") + vars.get(0).complexType should be ("Children") + vars.get(0).getter should be ("getChildren") + vars.get(0).setter should be ("setChildren") + vars.get(0).datatype should be ("List[Children]") + vars.get(0).name should be ("children") + vars.get(0).defaultValue should be ("new ListBuffer[Children]() ") + vars.get(0).baseType should be ("List") + vars.get(0).containerType should be ("array") + vars.get(0).required should equal (false) + vars.get(0).isContainer should equal (true) + } + + it should "convert a model with complex map property" in { + val model = new ModelImpl() + .description("a sample model") + .property("children", new MapProperty() + .additionalProperties(new RefProperty("#/definitions/Children"))) + + val codegen = new ScalaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("a sample model") + cm.vars.size should be (1) + (cm.imports.asScala.toSet & Set("Children")).size should be (1) + + val vars = cm.vars + vars.get(0).baseName should be ("children") + vars.get(0).complexType should be ("Children") + vars.get(0).getter should be ("getChildren") + vars.get(0).setter should be ("setChildren") + vars.get(0).datatype should be ("Map[String, Children]") + vars.get(0).name should be ("children") + vars.get(0).defaultValue should be ("new HashMap[String, Children]() ") + vars.get(0).baseType should be ("Map") + vars.get(0).containerType should be ("map") + vars.get(0).required should equal (false) + vars.get(0).isContainer should equal (true) + vars.get(0).isNotContainer should be (null) + } + + it should "convert an array model" in { + val model = new ArrayModel() + .description("an array model") + .items(new RefProperty("#/definitions/Children")) + val codegen = new ScalaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("an array model") + cm.vars.size should be (0) + cm.parent should be ("ListBuffer[Children]") + cm.imports.size should be (3) + (cm.imports.asScala.toSet & Set("List", "ListBuffer", "Children")).size should be (3) + } + + it should "convert an map model" in { + val model = new ModelImpl() + .description("an map model") + .additionalProperties(new RefProperty("#/definitions/Children")) + + val codegen = new ScalaClientCodegen() + val cm = codegen.fromModel("sample", model) + + cm.name should be ("sample") + cm.classname should be ("Sample") + cm.description should be ("an map model") + cm.vars.size should be (0) + cm.parent should be ("HashMap[String, Children]") + cm.imports.size should be (2) + (cm.imports.asScala.toSet & Set("HashMap", "Children")).size should be (2) + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/scala/staticDocs/StaticOperationTest.scala b/modules/swagger-codegen/src/test/scala/staticDocs/StaticOperationTest.scala new file mode 100644 index 00000000000..f46201faa5b --- /dev/null +++ b/modules/swagger-codegen/src/test/scala/staticDocs/StaticOperationTest.scala @@ -0,0 +1,65 @@ +package staticDocs + +import com.wordnik.swagger.codegen.languages.StaticDocCodegen +import com.wordnik.swagger.util.Json +import com.wordnik.swagger.models._ +import com.wordnik.swagger.models.properties._ + +import org.junit.runner.RunWith +import org.scalatest.junit.JUnitRunner +import org.scalatest.FlatSpec +import org.scalatest.Matchers + +import scala.collection.JavaConverters._ + +@RunWith(classOf[JUnitRunner]) +class StaticOperationTest extends FlatSpec with Matchers { + it should "convert a string parameter" in { + val property = new StringProperty() + + val codegen = new StaticDocCodegen() + val cp = codegen.fromProperty("property", property) + + cp.baseName should be ("property") + cp.datatype should be ("String") + cp.name should be ("property") + cp.baseType should be ("string") + cp.isNotContainer should equal (true) + } + + it should "convert a complex parameter" in { + val property = new RefProperty("Children") + + val codegen = new StaticDocCodegen() + val cp = codegen.fromProperty("property", property) + + cp.baseName should be ("property") + cp.complexType should be ("Children") + cp.getter should be ("getProperty") + cp.setter should be ("setProperty") + cp.datatype should be ("Children") + cp.name should be ("property") + cp.defaultValue should be ("null") + cp.baseType should be ("Children") + cp.isNotContainer should equal (true) + } + + it should "convert a complex list parameter" in { + val property = new ArrayProperty(). + items(new RefProperty("Children")) + + val codegen = new StaticDocCodegen() + val cp = codegen.fromProperty("property", property) + + cp.baseName should be ("property") + cp.complexType should be ("Children") + cp.getter should be ("getProperty") + cp.setter should be ("setProperty") + cp.datatype should be ("List") + cp.name should be ("property") + cp.baseType should be ("array") + cp.containerType should be ("array") + cp.isContainer should equal (true) + + } +} \ No newline at end of file